题意:找出m个不同的n位2进制数,异或值中前v个为1,其余为0的方案数,答案 % 10567201。。
思路:比赛时第一感觉是用容斥原理做的,然后推呀推,搞了2个小时还是错了。。赛后才知道递推才是正解(也许容斥是可以的,是我太弱了,推不出吧)
因为异或的特性,所以这m个数异或为x(前v个为1,其余为0的m位数),相当于这m个数异或x为0,。。
也就是说如果知道m-1个数,第m个数也唯一被确定了。。
假设f[m]为m个数的方案数,那么不考虑重复的情况下,f[m] = C(2^n, m-1)
那么如何去除重复了,如果出现重复(一定最多只有两个数重复),那么这两个书异或值为0,发现什么了没有。。
也就是去掉这两个数,就是f[m-2]了吧。。
除此之外,对于合法的每一组方案,会算m次吧
so,f[m] = (C(2^n, m-1) - f[m-2] * (2^n - (m-2))) / m;
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <cmath> 6 #include <algorithm> 7 #include <vector> 8 #include <cstdlib> 9 #include <sstream> 10 #include <fstream> 11 #include <list> 12 #include <deque> 13 #include <queue> 14 #include <stack> 15 #include <map> 16 #include <set> 17 #include <bitset> 18 #include <cctype> 19 #include <ctime> 20 #include <utility> 21 #define M0(x) memset(x, 0, sizeof(x)) 22 #define clr(x,y) memset(x, y, sizeof(x)) 23 #define P 10567201 24 #define N 1010 25 using namespace std; 26 long long c[1010][1010], two[1010]; 27 int n, m, v; 28 long long f[N+5], inv[N+5]; 29 using namespace std; 30 31 void get_inv(){ 32 inv[1] = 1; 33 for (int i = 2; i < N; ++i) 34 inv[i] = (P - P / i) * inv[P % i] % P; 35 } 36 37 void pre_do(){ 38 get_inv(); 39 two[0] = 1; 40 for (int i = 1; i < N; ++i){ 41 two[i] = (two[i-1] << 1); 42 if (two[i] >= P) two[i] -= P; 43 } 44 for (int i = 1; i < N; ++i){ 45 c[i][0] = 1; 46 for (int j = 1; j < N; ++j) 47 c[i][j] = c[i][j-1] * (two[i]-j+1) % P * inv[j] % P; 48 } 49 } 50 51 void solve(){ 52 if (v == 0) f[0] = 1; 53 else f[0] = 0; 54 f[1] = 1; 55 for (int i = 2; i <= m; ++i){ 56 long long same = f[i-2] * (two[n]-i+2) % P; 57 f[i] = (c[n][i-1] - same) * inv[i] % P; 58 } 59 f[m] += (f[m] < 0 ? P : 0); 60 printf("%I64d ", f[m]); 61 } 62 63 int main(){ 64 // freopen("a.in","r",stdin); 65 // freopen("a.out","w",stdout); 66 pre_do(); 67 while (scanf("%d%d%d", &n, &m, &v) != EOF){ 68 if (!(n+m+v)) break; 69 solve(); 70 } 71 return 0; 72 }