Vijos 1286 座位安排(状态压缩DP)
先是一个转化,将n和m中较小的的为m这样状态数会小于1<<9。看题后,是嘛想法都啊没有。。看了DISUSS中有人提到这点。。。
写完,调了一下,尝试了几次,发现有两组过不了。想想极限数据,可能还是会爆__int64,然后乱搞改编一下,求组合数模版。。。水过了。。。
还是用STL中vector写的。。。以后还是用数组把。。。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <vector> 5 using namespace std; 6 #define LL unsigned __int64 7 LL dp1[1<<9][21]; 8 LL dp2[1<<9][21]; 9 int o[1<<9]; 10 vector<int> ve; 11 vector<int>::iterator it1,it2; 12 LL gcd(LL a,LL b) 13 { 14 return b == 0 ? a:gcd(b,a%b); 15 } 16 LL c(int n,int m) 17 { 18 int i,j; 19 if(n-m < m) 20 m = n-m; 21 LL s; 22 for(i = 1,s = 1,j = 1;j <= m;n--,j ++) 23 { 24 s = s*n; 25 while(s%i == 0&&i <= m)//这里防止爆精度 26 { 27 s = s/i; 28 i ++; 29 } 30 } 31 return s; 32 } 33 int main() 34 { 35 int n,m,k,i,j,t; 36 LL ans; 37 scanf("%d%d%d",&n,&m,&k); 38 if(m > n) 39 { 40 t = m; 41 m = n; 42 n = t; 43 } 44 for(i = 0; i < 1<<m; i ++) 45 { 46 for(j = 0; j < m; j ++) 47 { 48 if(i&(1<<j)) 49 o[i] ++; 50 } 51 } 52 for(i = 0; i < 1<<m; i ++) 53 { 54 if(i&(i>>1)||i&(i<<1)) 55 ; 56 else 57 { 58 if(o[i] <= k) 59 { 60 dp1[i][o[i]] = 1; 61 ve.push_back(i); 62 } 63 } 64 } 65 for(i = 2; i <= n; i ++) 66 { 67 for(it1 = ve.begin(); it1 != ve.end(); it1 ++) 68 { 69 for(it2 = ve.begin(); it2 != ve.end(); it2 ++) 70 { 71 for(j = 0; j <= k; j ++) 72 { 73 if((*it1)&(*it2)) 74 ; 75 else 76 { 77 if(o[(*it2)]+j <= k) 78 dp2[(*it2)][o[(*it2)]+j] += dp1[(*it1)][j]; 79 } 80 } 81 } 82 } 83 for(it1 = ve.begin(); it1 != ve.end(); it1 ++) 84 { 85 for(j = 0; j <= k; j ++) 86 { 87 dp1[(*it1)][j] = dp2[(*it1)][j]; 88 dp2[(*it1)][j] = 0; 89 } 90 } 91 } 92 ans = 0; 93 for(i = 0; i < 1<<m; i ++) 94 { 95 ans += dp1[i][k]; 96 } 97 LL temp,comb; 98 comb = c(m*n,k); 99 temp = gcd(ans,comb); 100 if(ans != 0) 101 printf("%I64d/%I64d\n",comb/temp,ans/temp); 102 else 103 printf("Impossible!\n"); 104 return 0; 105 }