ZZUOJ 10509 组合数学+乘法逆元
链接:
http://acm.zzu.edu.cn:8000/problem.php?id=10509
题意:
给定n个正整数,a1 a2 ... an,从中选取k个数 , ai1 ai2 ai3 ... Aik,其中(1<=i1<i2<i3<...<ik<=n),u=ai1 ^ai2 ^ai3 ^... ^Aik,将异或和为u 的序列(i1,i2,...,ik)的个数记为f(u),求∑(f(u)*u) (枚举u从1到正无穷) ,由于数值可能非常大,输出对1000000007 取模后的余数(即结果mod 1000000007)。
题解:
统计每一位的1的个数,对于每一位,计算有多少种异或和为1的情况,只有有奇数个1的时候异或和才为1,所以就要用的组合数了
这个可以通过逆元快速求的C(n,m)
代码:
31 ll n, k; 32 ll a[MAXN]; 33 ll b[MAXN]; 34 35 ll extgcd(ll a, ll b, ll &x, ll &y) { 36 ll d = a; 37 if (b) d = extgcd(b, a%b, y, x), y -= (a / b) * x; 38 else x = 1, y = 0; 39 return d; 40 } 41 42 ll inv(ll a) { 43 ll x, y; 44 extgcd(a, MOD, x, y); 45 return (MOD + x%MOD) % MOD; 46 } 47 48 ll C(ll n, ll m) { 49 if (n < m) return 0; 50 ll ret = (b[n] * inv(b[m])) % MOD; 51 ret = (ret*inv(b[n - m])) % MOD; 52 return ret; 53 } 54 55 int main() { 56 b[0] = 1; 57 rep(i, 1, MAXN) b[i] = (b[i - 1] * i) % MOD; 58 scanf("%d%d", &n, &k); 59 rep(i, 0, n) scanf("%d", a + i); 60 ll ans = 0; 61 ll cnt = 1; 62 rep(i, 0, 25) { 63 ll a1 = 0; 64 rep(j, 0, n) { 65 if (a[j] & 1) a1++; 66 a[j] >>= 1; 67 } 68 if (!a1) continue; 69 ll a0 = n - a1; 70 71 ll sum = 0; 72 for (ll p = 1; p <= k; p += 2) { 73 ll q = k - p; 74 if (q > a0) continue; 75 sum = (sum + C(a1, p) * C(a0, q)) % MOD; 76 } 77 ans = (ans + sum*cnt) % MOD; 78 cnt <<= 1; 79 } 80 printf("%d\n", ans); 81 return 0; 82 }