zoukankan      html  css  js  c++  java
  • hihoCoder 1549 或运算和

    #1549 : 或运算和

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    给定N个数A1...AN (0 <= Ai < 220) 和一个正整数K,我们用Ans[i]表示有多少种从这N个数中选取K个数的方案,满足这K个数的或运算和正好为i。

    你能对于每一个i(0 <= i < 220)都计算出Ans[i]的值吗?

    为了简化输出,你只需要输出Σ(Ans[i] * i) 除以1000000007的余数。

    输入

    第一行一个数T(<=10),表示数据组数

    对于每一组数据:

    第一行两个数N,K(1<=N<=100,000,K<=1000)

    第二行N个数A1...AN (0 <= Ai < 220)

    输出

    一个数表示答案

    样例输入

    2
    3 2
    1 2 3
    4 2
    1 2 4 5

    样例输出

    9

    31

    //其实,若是理解了,很容易做出来

    直接分析答案,

    ∑(ANS[i] * i ) = ∑(ANS[i] * (2p1+2p2+2p3+...+2px)) (Pi 为互不相同的自然数)

    = 20 * (Ans[0]+ANS[1]+...+ ANS[220-1])

    +21 * (Ans[0]+ANS[1]+...+ ANS[220-1])

    +...

    +219 * (Ans[0]+ANS[1]+...+ ANS[220-1])

    然后,发现,(Ans[0]+ANS[1]+...+ ANS[220-1])这部分,代表的意思是,n 个数中选 k 个数或出 0 -- 220-1 的种数。选 k 个数不管如何,或出来肯定在 0 - 220-1 之中,所以 2i * (Ans[0]+ANS[1]+...+ ANS[220-1]) 就是 n 个数中,转二进制,第 i 位选 k 个或出 1 的种数,然后就简单的排列组合,求逆元,累加即可。

    或者简单的撕拷,选 k 个数,组成了一种 i ,i 是由 (2p1+2p2+2p3+...+2px)组成,答案中就包含了这部分,所以,找到所有选 k 个数可以让 x (0-19)位变为 1 的种数,再乘以权值,即为答案,其实这就是算贡献,还得好好练啊!

     1 # include <cstdio>
     2 # include <cstring>
     3 # include <cstdlib>
     4 # include <iostream>
     5 # include <vector>
     6 # include <queue>
     7 # include <stack>
     8 # include <map>
     9 # include <bitset>
    10 # include <set>
    11 # include <cmath>
    12 # include <algorithm>
    13 using namespace std;
    14 #define lowbit(x) ((x)&(-x))
    15 #define pi acos(-1.0)
    16 #define eps 1e-8
    17 #define MOD 1000000007
    18 #define INF 0x3f3f3f3f
    19 #define LL long long
    20 inline int Scan() {
    21     int x=0,f=1; char ch=getchar();
    22     while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    23     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    24     return x*f;
    25 }
    26 inline void Out(int a) {
    27     if(a<0) {putchar('-'); a=-a;}
    28     if(a>=10) Out(a/10);
    29     putchar(a%10+'0');
    30 }
    31 #define MX 100005
    32 //Code begin...
    33 int n,k;
    34 int a[MX];
    35 
    36 LL qk_mi(LL x,LL y)
    37 {
    38     LL res = 1;
    39     while (y)
    40     {
    41         if (y&1) res = res*x%MOD;
    42         x = x*x%MOD;
    43         y/=2;
    44     }
    45     return res;
    46 }
    47 
    48 LL C(LL x,LL y)// m   n
    49 {
    50     if (x>y) return 0LL;
    51     LL res =1;
    52     for (int i=1;i<=y;i++)
    53         res = (res*i)%MOD;
    54     LL mj = 1,mnj = 1;
    55     for (int i=1;i<=x;i++)
    56         mj = (mj*i)%MOD;
    57     for (int i=1;i<=(y-x);i++)
    58         mnj = (mnj*i)%MOD;
    59     mj = qk_mi(mj,MOD-2); mnj = qk_mi(mnj,MOD-2);
    60     res = (res*mj%MOD) * mnj %MOD;
    61     return res;
    62 }
    63 
    64 LL slove(int x,int y)
    65 {
    66     LL res = C(k,x+y);
    67     res = (res +MOD -C(k,x))%MOD;
    68     return res;
    69 }
    70 
    71 int main()
    72 {
    73     int T=Scan();
    74     while(T--)
    75     {
    76         n = Scan();k = Scan();
    77         for (int i=0;i<n;i++)
    78             a[i] = Scan();
    79         LL ans = 0;
    80         for (int i=0;i<20;i++)
    81         {
    82             int zero=0,one=0;
    83             for (int j=0;j<n;j++)
    84                 if ((a[j]>>i)&1) one++;
    85                 else zero++;
    86             ans = (ans + (1LL<<i)*slove(zero,one)%MOD )%MOD;
    87         }
    88         printf("%lld
    ",ans);
    89     }
    90     return 0;
    91 }
    View Code
  • 相关阅读:
    javamail发送邮件
    java复制文件夹中的所有文件和文件夹到另一个文件夹中
    jsp中使用out和response.getOutputStream的方法
    PHP数组用法
    PHP中的session
    java中list按照某个属性排序方法
    java读取xml文件内容
    C#实现验证码
    java实现验证码功能
    Java IO(四)------字节输入输出流
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/7324216.html
Copyright © 2011-2022 走看看