明天要模拟,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;
 }