【JZOJ 5414】【NOIP2017提高A组集训10.22】幸运值

Description

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

Solution

这题先拆位,
对于每一位,只有当选了单数个1时才不为0,
那就统计一下总共有多少个1,枚举选多少个,再用组合数即可,
注意组合数爆掉的情况,即例如在10个数中选20个,

复杂度: O(nlog(ai))

Code

#include 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int N=100500,mo=998244353;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
int a[N];
LL ans;
LL jc[N],jcn[N];
LL ksm(LL q,int w)
{
    LL ans=1;
    for(q%=mo;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
    return ans;
}
LL C(int m,int n){return jc[m]*jcn[n]%mo*jcn[m-n]%mo;}
int main()
{
    int q,w;
    read(n),read(m);
    fo(i,1,n)read(a[i]);
    jc[0]=1;fo(i,1,n+1)jc[i]=jc[i-1]*(LL)i%mo;
    jcn[n+1]=ksm(jc[n+1],mo-2);
    fod(i,n,0)jcn[i]=jcn[i+1]*(LL)(i+1)%mo;
    LL er=1;
    fo(II,1,31)
    {
        q=0;
        fo(i,1,n)if(a[i]&er)q++;
        w=n-q;
        for(int i=1;i<=q&&i<=m;i+=2)if(m-i<=w)ans=(ans+er*C(q,i)%mo*C(w,m-i))%mo;
        er<<=1;
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(杂题)