题意:给定n*n的棋盘,放置k个象的方案数。象的攻击为对角线。
黑书p243例题
总结:
dp,有的时候可以把阶段排序,这样分阶段,可以减少状态表示。
技巧,mark!
另外sgu上很多题目都是用大数啊,这里贴了个大数的模板。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #include<string.h> #include<math.h> #define LL long long #define M 55 #define N 2555 #define base 10000 struct bign{ int l,a[M]; bign(){ memset(a,0,sizeof(a)); l = 0; } bign(int x){ memset(a,0,sizeof(a)); for(l= 0; x; x/= base) a[l++] = x%base; if(!l) l++; } bign operator = (bign x){ memcpy(a,x.a,sizeof(a)); l = x.l; return *this; } bign operator + (bign x){ bign res; int i,cy = 0; for(i = 0; i<l||i<x.l||cy > 0; i++){ if(i < l) cy += a[i]; if(i < x.l) cy += x.a[i]; res.a[i] = cy %base; cy /= base; } res.l = i; return res; } bign operator *(bign x){ bign res; res.l = 0; if(0 == x.l){ res.a[0] = 0; x.l = 1; return res; } for(int i = 0; i < l; i++) for(int j = 0,cy = 0; j <x.l||cy>0; j++,cy/=base){ if(j < x.l) cy += a[i]*x.a[j]; if(i+j < res.l) cy += res.a[i+j]; if(i+j >= res.l) res.a[res.l++] = cy%base; else res.a[i+j] = cy%base; } return res; } void print(){ int i; printf("%d",l==0?0:a[l-1]); for(i = l-2; i >= 0; i--) printf("%04d",a[i]); printf("\n"); } }; bign dpb[M][N],dpw[M][N]; int n,m; int w[M],b[M]; int wn,bn; int main() { int i,j; scanf("%d%d",&n,&m); wn = bn = 0; for (i=1;i<n;i+=2){ w[++wn] = i; w[++wn] = i; } if (i == n) w[++wn] = n; for (i=2;i<n;i+=2){ b[++bn] = i; b[++bn] = i; } if (i==n){ b[++bn] = n; } /* for (int i=1;i<=wn;i++){ printf("%d %d\n",i,w[i]); } for (int i=1;i<=bn;i++) { printf("%d %d\n",i,b[i]); } */ dpw[0][0] = 1; for (i=1;i<=wn;i++){ dpw[i][0] = 1; for (j=1;j<=w[i];j++) { dpw[i][j] = dpw[i-1][j] + dpw[i-1][j-1]*bign(w[i] - j +1); } } dpb[0][0] = 1; for (i=1;i<=bn;i++){ dpb[i][0] = 1; for (j=1;j<=b[i];j++){ dpb[i][j] = dpb[i-1][j] + dpb[i-1][j-1]*bign(b[i] - j + 1); } } bign ans = bign(0); for (int i=0;i<=m;i++){ ans = ans + dpw[wn][i]*dpb[bn][m-i]; } ans.print(); return 0; }