CF1336E Chiori and Doll Picking 题解
思路来自 ix35,orzorzorz。
好题,好题啊。
题意翻译说的很清楚了,直接说做法。
记
显然我们应该建出这个序列的线性基
则答案是
这个做法适用于
为了证明这个结论我们先证明引理:
引理证明:考虑线性空间任意异或一个数后线性空间不变,因此有
把线性空间中所有向量代入上式求和可以得到
两边同时
因此对于任意系数都有
这个引理有一个显然的推论:
再来考虑我们要证明的结论,发现
证明了这个结论我们再回来看我们要求的答案,可以得到
发现向量的每一位是本质相同的,因此
那么我们要求的答案就是
最后我们将两个做法合并,
正交线性基的一个构造方法是先对线性基高消使得主元所在的列只有一个
于是可以在
#include<iostream>
#include<cstdio>
using namespace std;
#define int long long
const int mod=998244353;
int n,m,a[55],w[200001],cnt,b[55],c[55][55],sum[55][55],p[200001],ans[55],res[55];
inline void init()
{
ios::sync_with_stdio(0);
cin.tie(0);
}
inline int read()
{
int x;
cin>>x;
return x;
}
inline int pw(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=1ll*res*a%mod;
b>>=1;
a=1ll*a*a%mod;
}
return res;
}
inline int Mod(int x)
{
return x>=mod? x-mod:x;
}
inline void ins(int x)
{
for(int i=m-1;~i;--i)
if(x>>i&1)
{
if(!a[i])
{
a[i]=x;
++cnt;
return;
}
x^=a[i];
}
}
inline void T()
{
for(int i=m-1;~i;--i)
for(int j=i-1;~j;--j)
if(a[i]>>j&1)
a[i]^=a[j];
for(int i=m-1;~i;--i)
if(!a[i])
{
b[i]=1ll<<i;
for(int j=m-1;~j;--j)
b[i]|=(a[j]>>i&1)<<j;
}
for(int i=0;i<m;++i)
a[i]=b[i];
}
inline void dfs1(int k,int val)
{
if(k>cnt)
{
int t=__builtin_popcountll(val);
ans[t]=Mod(ans[t]+p[n-cnt]);
return;
}
dfs1(k+1,val);
dfs1(k+1,val^b[k]);
}
inline void dfs2(int k,int val)
{
if(k>cnt)
{
int t=__builtin_popcountll(val);
++res[t];
return;
}
dfs2(k+1,val);
dfs2(k+1,val^b[k]);
}
signed main()
{
init();
n=read(),m=read();
p[0]=1;
for(int i=1;i<=n;++i)
p[i]=Mod(p[i-1]<<1);
if(!m)
{
cout<<p[n]<<'\n';
cout.flush();
return 0;
}
for(int i=1;i<=n;++i)
ins(w[i]=read());
if(cnt<=(m>>1))
{
int tmp=0;
for(int i=0;i<m;++i)
if(a[i])
b[++tmp]=a[i];
dfs1(1,0);
}
else
{
T();
cnt=m-cnt;
c[0][0]=1;
for(int i=1;i<=m;++i)
{
c[i][0]=1;
for(int j=1;j<=i;++j)
c[i][j]=Mod(c[i-1][j]+c[i-1][j-1]);
}
for(int i=0;i<=m;++i)
for(int j=0;j<=m;++j)
for(int k=0;k<=m;++k)
if(k<=i&&j-k<=m-i&&j-k>=0)
sum[i][j]=Mod(sum[i][j]+1ll*(k&1? mod-1:1)*c[i][k]%mod*c[m-i][j-k]%mod);
int tmp=0;
for(int i=0;i<m;++i)
if(a[i])
b[++tmp]=a[i];
dfs2(1,0);
int inv=pw(p[cnt],mod-2);
for(int i=0;i<=m;++i)
{
for(int j=0;j<=m;++j)
ans[i]=Mod(ans[i]+1ll*res[j]*sum[j][i]%mod);
ans[i]=1ll*ans[i]*inv%mod*p[n-(m-cnt)]%mod;
}
}
for(int i=0;i<=m;++i)
cout<<ans[i]<<" ";
cout<<'\n';
cout.flush();
return 0;
}