Bzoj1479: [Nerrc1997]Puncher打孔机
1479: [Nerrc1997]Puncher打孔机
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 22 Solved: 14
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
题解:
G0uv 表示每条边上都至少有一个格子被染色的u行v列的矩阵,总的染色方案数。
G1uv 表示每条边上都至少有一个格子被染色的u行v列的矩阵,其通过旋转180度保持不变的染色方案数。
G2uv 表示每条边上都至少有一个格子被染色的u行u列的矩阵,其通过旋转90度或270度保持不变的染色方案数。
G3uv 表示每条边上都至少有一个格子被染色的u行v列的矩阵,其通过上下翻转保持不变的染色方案数。
G4uv 表示每条边上都至少有一个格子被染色的u行v列的矩阵,其通过左右翻转保持不变的染色方案数。
G5uv 表示每条边上都至少有一个格子被染色的u行u列的矩阵,其通过沿某条对角线翻转保持不变的染色方案数。
求得所有的G值,F值就只需套用引理即可。而的求法也都大同小异。
• 求法:容斥原理!!!
就是应用容斥原理,将所有格子任意染色,减去第一行或者第u行或者第一列或者第v列没染色,再加上第1行和第u行均未染色……即:
旋转180度不变,实际上就是前个格子任意染色,然后剩下的格子染色情况则由这些格子旋转得到,同样需要应用容斥原理:
旋转90度或者270度,则是由左上角的个格子任意染色,然后剩下的格子染色情况则由这些格子旋转得到,同样需要应用容斥原理:
上下翻转,则是由上半部分的个格子任意染色,然后剩下的格子染色情况则由这些格子旋转得到,同样需要应用容斥原理:
左右翻转,则是由半边部分的个格子任意染色,然后剩下的格子染色情况则由这些格子旋转得到,同样需要应用容斥原理:
沿对角线翻转,则是由对角线上面部分的个格子任意染色,然后剩下的格子染色情况则由这些格子旋转得到,同样需要应用容斥原理:
完美解决!!!
参考文献: 《Puncher》解题报告
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdio> 6 #define ll long long 7 using namespace std; 8 ll ans; 9 int n,m; 10 int read() 11 { 12 int x=0,f=1; char ch; 13 while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') f=-1; 14 while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); 15 return x*f; 16 } 17 ll ksm(ll x,int k) 18 { 19 ll res=1; 20 for (int i=k; i; i>>=1,x*=x) if (i&1) res*=x; 21 return res; 22 } 23 ll get0(int u,int v) 24 { 25 ll res=0; 26 res=ksm(2,u*v) 27 -ksm(2,(u-1)*v)*2-ksm(2,u*(v-1))*2 28 +ksm(2,(u-1)*(v-1))*4+ksm(2,(u-2)*v)+ksm(2,u*(v-2)) 29 -ksm(2,(u-2)*(v-1))*2-ksm(2,(u-1)*(v-2))*2 30 +ksm(2,(u-2)*(v-2)); 31 return res; 32 } 33 ll get1(int u,int v) 34 { 35 ll res=0; 36 res=ksm(2,ceil(u*v/2.0)) 37 -ksm(2,ceil(u*v/2.0)-u)-ksm(2,ceil(u*v/2.0)-v) 38 +ksm(2,ceil(u*v/2.0)-u-v+2); 39 return res; 40 } 41 ll get2(int u,int v) 42 { 43 ll res=0; 44 res=ksm(2,ceil(u*v/4.0))-ksm(2,(ceil(u*v/4.0)-u+1)); 45 return res; 46 } 47 ll get3(int u,int v) 48 { 49 ll res=0; 50 res=ksm(2,ceil(u/2.0)*v) 51 -ksm(2,ceil(u/2.0)*(v-1))*2-ksm(2,(ceil(u/2.0)-1)*v) 52 +ksm(2,ceil(u/2.0)*(v-2))+ksm(2,(ceil(u/2.0)-1)*(v-1))*2 53 -ksm(2,(ceil(u/2.0)-1)*(v-2)); 54 return res; 55 } 56 ll get4(int u,int v) 57 { 58 ll res=0; 59 res=ksm(2,u*ceil(v/2.0)) 60 -ksm(2,(u-1)*ceil(v/2.0))*2-ksm(2,u*(ceil(v/2.0)-1)) 61 +ksm(2,(u-2)*ceil(v/2.0))+ksm(2,(u-1)*(ceil(v/2.0)-1))*2 62 -ksm(2,(u-2)*(ceil(v/2.0)-1)); 63 return res; 64 } 65 ll get5(int u,int v) 66 { 67 ll res=0; 68 res=ksm(2,u*(u+1)/2.0)-ksm(2,(u-1)*u/2.0)*2+ksm(2,(u-2)*(u-1)/2.0); 69 return res; 70 } 71 ll get(int u,int v) 72 { 73 ll res=0; 74 if (v==1) 75 { 76 if (u==1) return 1; 77 return (ksm(2,u-2)+ksm(2,(u+1)/2.0-1))/2.0; 78 } 79 else 80 { 81 if (u==v) 82 { 83 res=(get0(u,v)+get1(u,v)+2*get2(u,v)+get3(u,v)+get4(u,v)+2*get5(u,v)); 84 return res/8; 85 } 86 else if (u>v) 87 { 88 res=(get0(u,v)+get1(u,v)+get3(u,v)+get4(u,v)); 89 return res/4; 90 } 91 } 92 } 93 int main() 94 { 95 n=read(); m=read(); 96 for (int u=1; u<=max(n,m); u++) 97 for (int v=1; v<=min(u,min(n,m)); v++) 98 ans+=get(u,v); 99 printf("%lld\n",ans); 100 return 0; 101 }