明天要模拟,n年未碰电脑,先不学新的了。。。。
1.错排问题
dp最棒了
code:
#include
#include
#include
#include
#include
using namespace std;
const int M=INT_MAX;
long long f[25][25]={ };//f[i][j]表示有i个数,其中j个数可以随便填
int jc[22];
void solve(){
jc[1]=1;
for(int i=2;i<=20;i++){
jc[i]=jc[i-1] * i;
}
}
long long dp(int num,int a){
if(f[num][a]!=0) return f[num][a];
if(num==a) return jc[num];//都自由则转化为阶乘问题
long long res=0;
if(a!=0){
res += a * dp(num-1,a);
}//讨论不可自由填的那一位填什么
if(num>a+1){
res += (num-1-a) * dp(num-1,a+1);
}
f[num][a]=res;
return res;
}
int main(){
f[0][0]=1;
f[1][0]=0;
solve();//我这行一开始忘打了,结果调了半天。。。
int n;
scanf("%d",&n);
long long ans=dp(n,0);
printf("%lld",ans);
return 0;
}
2.奇怪的汉诺塔
与3塔的转换与取最小值是我没想到的。。。
#include
#include
#include
#include
#include
using namespace std;
const int M=INT_MAX;
int main(){
int f[15] = { };
int k[15] = { };
for(int i=1;i<=12;i++){
k[i]=M;
}
f[1]=1;
f[2]=3;
k[1]=1;
for(int i=3;i<=12;i++){
f[i] = 2 * f[i-1] + 1;
}
for(int i=2;i<=12;i++){
for(int j=1;j<=i;j++){
k[i] = min(k[i],2*k[j]+f[i-j]);
}
}
for(int i=1;i<=12;i++){
printf("%d\n",k[i]);
}
return 0;
}
数的划分
一遍AC针不戳(dp太香了)
#include
#include
#include
#include
#include
using namespace std;
const int M = INT_MAX;
int f[202][202][8] = {};
long long dp(int min, int left, int num) {
if (f[min][left][num] != 0)
return f[min][left][num];
if (num == 1)
return 1;
int res = 0;
for (int i = min; i <= left / num; i++) {
res += dp(i, left - i, num - 1);
}
return f[min][left][num] = res;
}
int main() {
int a, b;
scanf("%d%d", &a, &b);
printf("%lld", dp(1, a, b));
return 0;
}
4.传球游戏
一开始一直在讨论奇偶性和转圈上纠结。。。
#include
#include
#include
#include
#include
using namespace std;
const int M = INT_MAX;
int main() {
int m, n;
long long f[50][50];
scanf("%d%d", &n, &m);
f[0][1] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (j == 1)
f[i][j] = f[i - 1][n] + f[i - 1][2];
else if (j == n)
f[i][j] = f[i - 1][n - 1] + f[i - 1][1];
else
f[i][j] = f[i - 1][j - 1] + f[i - 1][j + 1];
}
}
printf("%lld", f[m][1]);
return 0;
}
平铺方案
opj原题,直接水掉~~
#include
#include
#include
#include
using namespace std;
int ans[1001], x[300][1000];
int pus(int s1[], int s2[]) {
int i;
memset(ans, 0, sizeof(ans));
int l1 = 500;
while (s1[l1] == 0) l1–;
int l2 = 500;
while (s2[l2] == 0) l2–;
for (i = 0; i <= max(l1, l2); i++) {
ans[i] += s1[i] + s2[i];
if (ans[i] >= 10) {
ans[i] -= 10;
ans[i + 1] += 1;
}
}
int k = i + 5;
while (ans[k] == 0) k–;
return k;
}
void solve() {
for (int i = 0; i <= 300; i++) {
for (int j = 0; j <= 500; j++) {
x[i][j] = 0;
}
}
x[0][0] = 1;
x[1][0] = 1;
for (int i = 2; i <= 252; i++) {
if (i == 23) {
int o = 15;
}
if (i == 20) {
int l = 15;
}
int m = pus(x[i - 2], x[i - 1]);
for (int j = 0; j <= m; j++) {
x[i][j] = ans[j];
}
m = pus(x[i], x[i - 2]);
for (int j = 0; j <= m; j++) {
x[i][j] = ans[j];
}
}
}
int main() {
solve();
int p;
while (scanf("%d", &p) != EOF) {
int z = 500;
while (x[p][z] == 0) z–;
for (int i = z; i >= 0; i–) {
printf("%d", x[p][i]);
}
printf("\n");
}
return 0;
}