[dp][组合数] Jzoj P4271 魔法阵
题解
- 第一眼,看到题目,又是xjb乱搞的数论题
- 看了看数据范围,果断水k<=1的点,其实就是每次+24
- 题目大意:就是给你一个N,要你创造出一个
-
1. 在直角坐标系xOy 中,画4 条线段:[(0,0), (2^n,0)], [(0, 0), (-2^n, 0)],[(0, 0), (0, 2^n)], [(0, 0), (0,-2^n)]。
2. 对于所有的i = 1, 2, ......, n,画两个正方形,一个以(0, 2^i), (0,-2^i),(2^i, 0), (-2^i, 0) 为顶点,另一个以(-2i-1,-2i-1),(-2i-1,2i-1), (2i-1,-2i-1)(2i-1,2i-1) 为顶点。
3. 画一个以(1, 0), (-1, 0), (0,-1), (0, 1) 为顶点的正方形。 - 现在给这个正方形里的三角形染色,问有多少中不同的情况
- 对于图中的三角形,我们可以先做一个分类
- ①经过源点的三角形,后面统称源三角形
- ②不经过源点的三角形,一级三角形(只有一个三角形组成),二级三角形(只有两个三角形组成)。。。
- 其实没有其它三角形的组成了,不信的可以手画一下
- 可以考虑从极端的n=0开始
- 那我们现在可以考虑从i转移到i+1
- 那么转移后必定会出现源三角形、一级三角形、二级三角形
- 对于第i个正方形在忽略了不能拓展的三角形以后,都为形成一个较大的n=0的形状
- 那么拓展后的绝对会与上面n=0时的某一种方案同构
- 这样的话,我们就可以不用一下子求出当前第i个正方形选三角形的方案
- 可以考虑从小正方形每次向大正方形转移
- 可以用dp
- 设f[i][j][k]表示当前拓展到第i层,总共选了j个三角形,能够拓展的源三角形的形状为编号j(也就是以上10中同构方案的标号)的方案数
- 考虑如何转移
- 从上面可以知道源三角形拓展后可以成为另一种同构方案
- 那么可以枚举同构方案,判断两种情况是否可以拓展
- 对于答案肯定不只是有源三角形的方案数,还有一级三角形和二级三角形的方案数,那么怎么求?在循环里求吗?
- 那肯定会炸,知道对于一种形态,它们所拥有的一级三角形和二级三角形的个数必定是相同的
- 那么就可以手推直接打表加入数组里,我们用dt1[i]和dt2[i]来记录
- 表示从第i个形态方式,剩下的一级三角形和二级三角形的个数
- 现在再来考虑下对于一种形态可以转换到哪几种形态
- 这个也像上面一样,直接手推出来,打表放入数组,用flag[i][j]记录
- 表示从第i种形态拓展到第j种形态的方案数
- 现在,就可以得出状态转移方程了
- f[i+1][j+s1+s2][label′]+f[i][j][label]×flag[label][label′]×C(s2,dt2[label′])×C(s1,dt1[label′])−2×s2→ f[i+1][j+s1+s2][label′]
- s1表示枚举当前加入多少个一级三角形,s2表示枚举加入多少个二级三角形,label表示拓展前的形态,label'表示拓展后的形态
- 注意一些边界情况:
- f[0][0][0] = 1,f[0][1][1] = 4 f[0][1][2] = 4,f[0][2][3] = 4 f[0][2][4] = 2,f[0][2][5] = 8 f[0][2][6] = 2,f[0][3][7] = 4 f[0][3][8] = 4,f[0][4][9] = 1
- 组合数就用杨辉三角来求就好了。。。
- 本蒟蒻太菜了,如果看不懂的详见题解
代码
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 const long long mo=1000000007; 6 int boo[10][10]={{1,0,0,0,0,0,0,0,0,0}, 7 {1,1,0,0,0,0,0,0,0,0}, 8 {1,0,1,0,0,0,0,0,0,0}, 9 {1,2,0,1,0,0,0,0,0,0}, 10 {1,2,0,0,1,0,0,0,0,0}, 11 {1,1,1,0,0,1,0,0,0,0}, 12 {1,0,2,0,0,0,1,0,0,0}, 13 {1,3,0,2,1,0,0,1,0,0}, 14 {1,2,1,1,0,2,0,0,1,0}, 15 {1,4,0,4,2,0,0,4,0,1}}; 16 int dt1[10]={12,9,6,6,6,3,0,3,0,0},dt2[10]={4,2,1,1,0,0,0,0,0,0},n,k; 17 long long f[210][210][210],c[210][210],ans; 18 int main() 19 { 20 freopen("magic.in","r",stdin); 21 freopen("magic.out","w",stdout); 22 scanf("%d%d",&n,&k); 23 c[0][0]=1; 24 for (int i=1;i<15;i++) 25 { 26 c[i][0]=1; 27 for (int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo; 28 } 29 f[0][0][0]=1; f[0][1][1]=4; f[0][1][2]=4; f[0][2][3]=4; f[0][2][4]=2; 30 f[0][2][5]=8; f[0][2][6]=2; f[0][3][7]=4; f[0][3][8]=4; f[0][4][9]=1; 31 for (int i=0;i<n;i++) 32 for (int j=0;j<10;j++) 33 for (int p=0;p<=k;p++) 34 if (f[i][p][j]) 35 for (int q=0;q<10;q++) 36 if (boo[j][q]) 37 { 38 int x=dt1[q],y=dt2[q]; 39 for (int r=0;r+p<=k&&r<=y;r++) 40 for (int t=0;t+p+r<=k&&t<=x-2*r;t++) 41 (f[i+1][t+p+r][q]+=(f[i][p][j]*c[y][r])%mo*c[x-2*r][t]*boo[j][q])%mo; 42 } 43 for (int i=0;i<10;i++) ans=(ans+f[n][k][i])%mo; 44 for (int i=1;i<=k;i++) ans=(ans*i)%mo; 45 printf("%lld",ans); 46 return 0; 47 }