srm555 div1
2012-09-23 02:11 macaroniz 阅读(240) 评论(0) 收藏 举报255pt:
构造出5^n的所有二进制串,然后dp即可。dp[i][j]表示考虑0~i构成的子串,分成j份是否可行,转移方程为dp[i][j] = dp[i][j] || (dp[i'][j-1] && (i'+1~i构成的子串是合法的))
1 vector<string> arrPow; 2 bool dp[55][55]; 3 class CuttingBitString 4 { 5 public: 6 string s; 7 void getArrPow() 8 { 9 arrPow.clear(); 10 unsigned long long k = 1; 11 for(int i = 0;i <= 25;i++) 12 { 13 string strA = ""; 14 unsigned long long tmp = k; 15 while(tmp != 0) 16 { 17 if(tmp % 2 == 0) strA += "0"; 18 else strA += "1"; 19 tmp = tmp / 2; 20 } 21 string strB = ""; 22 bool flag = false; 23 for(int j = strA.length()-1;j >= 0;j--) 24 { 25 if(strA[j] != '0') 26 flag = true; 27 if(flag) 28 strB += strA[j]; 29 } 30 arrPow.push_back(strB); 31 k*=5; 32 } 33 } 34 35 bool OK(int x,int y) 36 { 37 string str = ""; 38 for(int i = x;i <= y;i++) 39 str += s[i]; 40 for(int i = 0;i < arrPow.size();i++) 41 if(str == arrPow[i]) 42 return true; 43 return false; 44 } 45 int getmin(string _S) 46 { 47 s = _S; 48 getArrPow(); 49 memset(dp,false,sizeof dp); 50 for(int i = 0;i < s.length();i++) 51 { 52 if(OK(0,i)) 53 { 54 dp[i][1] = true; 55 } 56 } 57 for(int i = 1;i < s.length();i++) 58 for(int j = 2;j <= s.length();j++) 59 for(int ii = 0;ii < i;ii++) 60 if(OK(ii+1,i) && dp[ii][j-1]) 61 dp[i][j] = true; 62 for(int i = 0;i <= s.length();i++) 63 { 64 if(dp[s.length()-1][i] == 1) 65 { 66 return i; 67 } 68 } 69 return -1; 70 } 71 }
555pt:
有个重要的观察:
经过一系列操作后,1的个数只与每一行和每一列操作次数的奇偶性有关,和具体次数无关。
因此我们可以推出公式,假设有且只有x行被操作了奇数次,有且只有y列被操作了奇数次,h为行数,w为列数,s为最后1的个数,那么有等式:x * (w-y) + (h-x) * y = s。
因此我们只需要枚举x,y就可以知道究竟哪些情况是合法的,假设我们知道了(x1,y1)是一组合法的情况,那么该情况下的方案数可以直接推得:
方案数 = calc(h,Rcount,x1) * calc(w,Ccount,y1)
其中 calc(n,m,x) 的抽象含义为将m个相同的球放在n个不同的盒子中,并且有且只有x个盒子中包含奇数个球。
计算方法为: calc(n,m,x) = C(x,n) * C(n-1,n+(m-x)/2 - 1), C(a,b)表示组合数
1 const int mo = 555555555; 2 3 int C[3000][3000]; 4 class XorBoard 5 { 6 public: 7 void init() 8 { 9 memset(C,0,sizeof C); 10 C[0][0] = 1; 11 for(int i = 1;i < 3000;i++) 12 { 13 C[i][0] = 1; 14 for(int j = 1;j <= i;j++) 15 C[i][j] = (C[i-1][j-1] + C[i-1][j]) % mo; 16 } 17 } 18 19 long long calc(int n,int m,int x) 20 { 21 if((m - x) % 2 != 0) return 0; 22 if(m < x) return 0; 23 int times = (m-x)/2; 24 long long ret = 1; 25 ret = (1ll * C[n+times-1][n-1] * C[n][x]) % mo; 26 return ret; 27 } 28 29 int minx(int a,int b) 30 { 31 return a < b ? a : b; 32 } 33 34 int count(int H, int W, int Rcount, int Ccount, int S) 35 { 36 init(); 37 int ans = 0; 38 int n = minx(H,Rcount),m = minx(W,Ccount); 39 int ii = ( Rcount % 2 == 0 )? 0 : 1; 40 int jj = ( Ccount % 2 == 0 )? 0 : 1; 41 for(int i = ii;i <= n;i++) 42 for(int j = jj ;j <= m;j++) 43 if((i * (W - j) + (H - i) * j) == S) 44 { 45 long long temp = (calc(H,Rcount,i) * calc(W,Ccount,j)) % mo; 46 ans = (ans + temp) % mo; 47 } 48 return ans; 49 } 50 }
浙公网安备 33010602011771号