校庆志愿者小Z在休息时间和同学们玩卡牌游戏。一共有n张卡牌,每张卡牌上有一个数Ai,每次可以从中选出k张卡牌。一种选取方案的幸运值为这k张卡牌上数的异或和。小Z想知道所有选取方案的幸运值之和除以998244353的余数。
这题先拆位,
对于每一位,只有当选了单数个1时才不为0,
那就统计一下总共有多少个1,枚举选多少个,再用组合数即可,
注意组合数爆掉的情况,即例如在10个数中选20个,
复杂度: O(nlog(ai))
#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;
}