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 }

 

posted @ 2017-09-09 22:41  Flowersea  阅读(260)  评论(0编辑  收藏  举报