【JZOJ5414】幸运值

Description

校庆志愿者小Z在休息时间和同学们玩卡牌游戏。一共有n张卡牌,每张卡牌上有一个数Ai,每次可以从中选出k张卡牌。一种选取方案的幸运值为这k张卡牌上数的异或和。小Z想知道所有选取方案的幸运值之和除以998244353的余数。

Solution

显然每一位是独立的。

于是拆位考虑,每一个为上选择奇数个1的方案数乘以该位权值即可。组合数可以轻松解决

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100010
#define mo 998244353
#define ll long long
using namespace std;
int cn[32];
ll jc[N],ny[N];
ll pow(ll x,int y){
    ll b=1;
    while(y){
        if(y&1) b=b*x%mo;
        y>>=1;
        x=x*x%mo;
    }
    return b;
}
ll c(int m,int n){
    if(m<n) return 0;
    return jc[m]*ny[m-n]%mo*ny[n]%mo;
}
int main()
{
    freopen("card.in","r",stdin);
    freopen("card.out","w",stdout);
    int n,k;
    scanf("%d %d",&n,&k);
    jc[0]=ny[0]=1;
    fo(i,1,n)
    {
        int x;
        scanf("%d",&x);
        fo(j,0,30)
        if(x&(1<<j)) cn[j]++;
        jc[i]=jc[i-1]*i%mo,ny[i]=pow(jc[i],mo-2);
    }
    ll ans=0;
    fo(j,0,30)
    {
        ll tmp=0;
        fo(i,1,k)
        tmp=(tmp+c(cn[j],i)*c(n-cn[j],k-i)%mo)%mo,i++;
        ans=(ans+(1<<j)%mo*tmp%mo)%mo;
    }
    printf("%lld",ans);
}
posted @ 2017-10-24 08:20  sadstone  阅读(40)  评论(0编辑  收藏  举报