zoukankan      html  css  js  c++  java
  • ZZUOJ 10509: xor运算统计

    题目链接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)。

    解题思路:由于ai < 1e6,所以ai的二进制位最多有20位。对每一位来说,假设这一位有xi个1,那么如果要使这一位为1,只需要从xi中选出来奇数个1(假设有k1个),从n-xi中选出来剩余n-k1个零,而这样子的选择方案共有C(xi,1)C(n-xi, k - 1) + C(xi,3)C(n-xi, k - 3) + …… .现在来考虑这样子如何计算结果,假设现在有四个数1 2 3 7, 对应二进制001,010,011,111,从中选k=3个数,那么所有结果总共有

    1^2^3 = 0, 1^2^7 = 4, 1^3^7 = 5, 2^3^7 = 6四个。那么显然答案应当是4+5+6。现在将4 5 6这三个数的二进制展开,得到:

    4 = 0x1 + 0x2 + 1x4

    5 = 1x1 + 0x2 + 1x4

    6 = 0x1 + 2x1 + 1x4

    到这儿大概已经能够发现,只需要将每一位可选的方案数目乘以其对应的2的幂,最后求和即是要求的答案。

    大致过程:扩展gcd求逆元并记录1~1e6的逆元;对于每个xi,使用组合数递推公式C(n,k) = C(n, k - 1) * (n - k + 1) / k 求xi以及n-xi的组合数值,复杂度O(n);最后累加求和即是答案。

    代码:

     1 const int maxn = 1e5 + 5;
     2 ll c[maxn], c1[maxn], inv[maxn];
     3 int n, k;
     4 int ti[20], a1[maxn];
     5 
     6 void ext_gcd(ll a, ll b, ll &d, ll &x, ll &y){
     7     if(b == 0){
     8         d = a; x = 1; y = 0;
     9     }
    10     else{
    11         ext_gcd(b, a % b, d, y, x); 
    12         y -= x * (a / b);
    13     }
    14 }
    15 int modinv(ll a){
    16     ll x, y, d;
    17     ext_gcd(a, -mod, d, x, y);
    18     if(d < 0) x = -x;
    19     return (x + mod) % mod;
    20 }
    21 void getinv(){
    22     for(int i = 2; i <= 1e5; i++)
    23         inv[i] = modinv(i);
    24 }
    25 void getcom(int x){
    26     c[0] = c1[0] = 1; c[1] = x; c1[1] = n - x;
    27     for(int i = 2; i <= x; i++) 
    28         c[i] = c[i - 1] % mod * (x - i + 1) % mod * inv[i] % mod;
    29     for(int i = 2; i <= n - x; i++)
    30         c1[i] = c1[i - 1] % mod * (n - x - i + 1) % mod * inv[i] % mod;
    31 }
    32 void solve(){
    33     getinv();
    34     memset(ti, 0, sizeof(ti));
    35     int mxcnt = 0;
    36     for(int i = 1; i <= n; i++){
    37         int x = a1[i], cnt = 0;
    38         while(x){
    39             ti[cnt++] += (x & 1);
    40             x >>= 1;
    41         }
    42         mxcnt = max(mxcnt, cnt);
    43     }
    44     ll ans = 0;
    45     for(int i = 0; i <= mxcnt; i++){
    46         int x = ti[i], tm = 1 << i;
    47         getcom(x);
    48         for(int i = 1; i <= k; i += 2){
    49             if(k - i > n - x || i > x) continue;
    50             ans = ans + c[i] % mod * c1[k - i] % mod * tm % mod;
    51             ans %= mod;
    52         }
    53     }
    54     printf("%lld
    ", ans);
    55 }
    56 int main(){
    57     scanf("%d %d", &n, &k);
    58     for(int i = 1; i <= n; i++)
    59         scanf("%d", &a1[i]);
    60     solve();
    61 }

    题目:

    10509: xor运算统计

    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 26  Solved: 5
    [Submit][Status][Web Board]

    Description

    给定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)。

    Input

    第一行两个整数n和k (1<=n,k<=10^5)
    第二行n个整数,表示a1 a2 ... An. (0<=ai<=10^6)

    Output

    输出一行一个整数,表示最后的答案.

    Sample Input

    4 2
    1 1 2 3
    

    Sample Output

    11

    HINT

     

    Source

    JXD

  • 相关阅读:
    Java常用的函数式接口
    Java网络编程的使用
    Java 多线程的使用
    VB.NET_DBUtil
    java 文件操作与IO流的常用方法
    JAVA Excel.xlsx 上传于下载
    java测试类
    Java11 HashMap源码分析(一、文档翻译)
    Canal实现Redis缓存实时更新(二)
    Canal实现Redis缓存实时更新(一)
  • 原文地址:https://www.cnblogs.com/bolderic/p/7514101.html
Copyright © 2011-2022 走看看