Jzoj5414 幸运值
校庆志愿者小Z在休息时间和同学们玩卡牌游戏。一共有n张卡牌,每张卡牌上有一个数Ai,每次可以从中选出k张卡牌。一种选取方案的幸运值为这k张卡牌上数的异或和。小Z想知道所有选取方案的幸运值之和除以998244353的余数。
为什么中间跳过了几道题?因为现在来不及改了先把过了的搬上来吧
套路:按位计算贡献
我们考虑,对于32个位置,选择k个异或为1的选法有多少
我们记cnt[i]表示第i位为1的数有多少个
那么显然,每一位对于答案的为2^i*方案数使得这一位为1
若要这一位为1,显然就需要选出奇数个1,那么我们假设选出了j个,那么0就要选k-j个
所以这一位答案就是2^i*(ΣC(j,cnt[i])*C(k-j,n-cnt[i]){j&1=1}
最后累加就好
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL __int128
#define M 998244353
using namespace std;
int cnt[32],n,s[100010],k;
LL js[100010],inv[100010],S=0,s1,s2;
LL pow(LL x,int k){
LL s=1;
for(;k;x=x*x%M,k>>=1) if(k&1) s=s*x%M;
return s;
}
LL C(int m,int n){
if(n<0 || m>n || m<0) return 0;
return js[n]*inv[m]%M*inv[n-m]%M;
}
int main(){
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
scanf("%d%d",&n,&k); --k;
for(int i=*js=*inv=1;i<=n;++i){
scanf("%d",s+i);
js[i]=js[i-1]*i%M;
for(int j=0;s[i];++j,s[i]>>=1) cnt[j]+=(s[i]&1);
}
inv[n]=pow(js[n],M-2);
for(int i=n;i;--i) inv[i-1]=inv[i]*i%M;
for(int i=0;i<32;++i){
s1=s2=0;
for(int j=0;j<=k;j+=2) s1=(s1+C(j,cnt[i]-1)*C(k-j,n-cnt[i]));
for(int j=1;j<=k;j+=2) s2=(s2+C(j,cnt[i])*C(k-j,n-cnt[i]-1));
S=(S+(1ll<<i)*(s1*cnt[i]%M+s2*(n-cnt[i])%M)%M)%M;
}
printf("%lld\n",(int)(S*pow(k+1,M-2)%M));
}