题目
题目链接:http://noip.ybtoj.com.cn/problems
思路
考虑按位计算贡献。假设第 \(i\) 位有 \(cnt0/1\) 个 \(0/1\),那么枚举选取 \(1\) 的个数,组合数计算即可。
时间复杂度 \(O(n\log A\log \operatorname{MOD})\),其中 \(A=\max(a_i)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010,MOD=998244353,LG=30;
int n,m,cnt1,cnt0,a[N];
ll ans,fac[N];
ll fpow(ll x,int k)
{
ll ans=1;
for (;k;k>>=1,x=x*x%MOD)
if (k&1) ans=ans*x%MOD;
return ans;
}
ll C(ll n,ll m)
{
ll inv=fpow(fac[m]*fac[n-m]%MOD,MOD-2);
return fac[n]*inv%MOD;
}
int main()
{
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
scanf("%d%d",&n,&m);
fac[0]=1;
for (int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%MOD;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=0;i<=LG;i++)
{
cnt0=cnt1=0;
for (int j=1;j<=n;j++)
if (a[j]&(1<<i)) cnt1++;
else cnt0++;
for (int j=1;j<=cnt1;j+=2)
{
int k=m-j;
if (cnt0<k || k<0) continue;
ans=(ans+(1LL<<i)%MOD*C(cnt1,j)%MOD*C(cnt0,k))%MOD;
}
}
printf("%lld",ans);
return 0;
}