CodeForces 1408I Bitwise Magic
题意
给定三个整数 \(n,k,c\) 和一个长度为 \(n\) 的序列 \(a\),保证 \(a_i\) 互不相同。可以操作 \(k\) 次,每次随机选择一个 \(a_i\) 变成 \(a_i-1\)。问最后的序列异或和为 \(0,\cdots 2^{c}-1\) 的概率。
\(\texttt{Data Range:}k,c\leq 16,k\leq a_i\leq 2^c-1,n\leq 2^{c}-k\)
题解
先来看一个显而易见的结论:对于 \(x\leq 2^c-1\),本质不同的 \(k\) 元组 \((x\oplus(x-1),x\oplus(x-2),\cdots,x\oplus(x-k))\) 的个数大约是 \(O(ck)\) 的。
首先注意到 \(x\oplus(x-1)\) 这个东西的取值只能是 \(2^t-1\) 的形式,其中 \(t=\log\operatorname{lowbit}(x)+1\)。考虑分类讨论。
-
如果 \(t>\log k\),因为 \(x\oplus (x-k)=(x\oplus (x-1))\oplus((x-1)\oplus(x-2))\cdots\),那么比 \(t\) 高的位不受影响,比 \(t\) 低的位因为是从 \(2^t-1\) 开始一个一个减的,与 \(x\) 无关,所有只有 \(O(c)\) 种取值。
-
如果 \(t\leq\log k\),那么这东西的取值只与 \(\log k\) 位往上走第一个 \(1\) 的位置和这 \(\log k\) 位的取值相关,所以取值为 \(O(c2^{\log k})=O(ck)\) 的。
经暴力计算可得 \(c=k=16\) 的时候只有 \(192\) 种本质不同的 \(k\) 元组。
由于直接数不好数,这里我们考虑每一次操作怎么改变答案的。容易看出如果对 \(a_i\) 操作 \(j\) 次的话会给原来的答案异或上 \(a_i\oplus (a_i-j)\)。
这个时候可以数一下本质不同操作序列的个数。由于操作序列随机排列是本质相同的,所以需要使用 EGF。为了方便,这里设 \(d_{i,j}=a_i\oplus(a_i-j)\),那么位置 \(i\) 的 EGF 为
这里 \(x\) 枚举的是这个位置的值,\(y\) 枚举的是操作次数。将每个位置的这些东西乘起来得到总共的 EGF:
其中 \(x\) 这个维度为异或卷积,\(y\) 为加法卷积。那么 \(v![x^u][y^v]\) 就表示操作了 \(v\) 次之后使得答案为 \(u\oplus a_1\oplus\cdots\oplus a_n\) 的方案数。注意到操作顺序不影响操作结果,在 EGF 的过程中去掉了这个影响,在最后统计的时候要乘回来。
考虑如何简化计算。对于每一个本质不同的 \(k\) 元组 \((x\oplus(x-1),x\oplus(x-2),\cdots,x\oplus(x-k))\) 来说,它对应的 EGF 是 \(x\) 操作若干次之后对答案的影响。于是我们可以设 \(G_i(x,y)\) 为第 \(i\) 中本质不同的 \(k\) 元组对应的 EGF,\(r_i\) 为出现次数,于是也可以这么表示 \(F\):
这个时候如果采用 \(O(k^2)\) 暴力先 \(\ln\) 再 \(\exp\) 求快速幂的话复杂度为 \(O(2^cck^3)\)。如果使用牛顿迭代的话因为常数原因,而且多项式次数较小跑得还没有暴力快。
对于某个 \(k\) 元组来说,考虑钦定一个 \(y\),再对 \(x\) 这个维度做 FWT。因为钦定了 \(y\) 的话只会有一个 \(x\) 的系数是形如 \(\frac{y^k}{k!}\) 的。根据 FWT 的相关理论,做完 FWT 之后中每一项都是形如 \(\pm\frac{y^k}{k!}\) 的。
这个时候就可以将每一个 \(k\) 元组对应到一个 \(1\) 和 \(-1\) 的序列上去,这个序列可以状压。将状压之后的东西放在一起快速幂即可。
代码
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast,unroll-loops")
#define pb emplace_back
#define popc __builtin_popcount
using namespace std;
typedef int ll;
typedef long long int li;
typedef vector<ll> vi;
const ll MAXN=65541,MOD=998244353;
map<vi,ll>mp;
ll n,kk,c,xorv,tot,fct,d,tp;
ll x[MAXN],invl[MAXN],finv[MAXN],f[MAXN],cnt[MAXN<<1];
ll st[201],sm[201],tmp[21],tmp2[21],tmp3[21];
li tmp4[21];
vi v[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline ll qpow(ll base,ll exponent)
{
ll res=1;
while(exponent)
{
if(exponent&1)
{
res=(li)res*base%MOD;
}
base=(li)base*base%MOD,exponent>>=1;
}
return res;
}
inline void ln(ll fd,ll *f,ll *res)
{
li r;
res[0]=0;
for(register int i=1;i<fd;i++)
{
r=0;
for(register int j=1;j<i;j++)
{
r+=(li)f[j]*res[i-j]%MOD;
}
res[i]=((li)i*f[i]%MOD-r%MOD+MOD)%MOD;
}
for(register int i=1;i<fd;i++)
{
res[i]=(li)res[i]*invl[i]%MOD;
}
}
inline void exp(ll fd,ll *f,ll *res)
{
li r;
res[0]=1;
for(register int i=1;i<fd;i++)
{
r=0,f[i]=(li)f[i]*i%MOD;
for(register int j=0;j<i;j++)
{
r+=(li)f[j+1]*res[i-j-1]%MOD;
}
res[i]=r%MOD*invl[i]%MOD;
}
}
int main()
{
n=read(),kk=read(),c=read(),invl[0]=invl[1]=finv[0]=finv[1]=fct=1;
for(register int i=2;i<65536;i++)
{
invl[i]=(MOD-(li)(MOD/i)*invl[MOD%i]%MOD)%MOD;
finv[i]=(li)finv[i-1]*invl[i]%MOD;
}
for(register int i=1;i<=n;i++)
{
xorv^=(x[i]=read());
for(register int j=0;j<=kk;j++)
{
v[i].pb(x[i]^(x[i]-j));
}
mp[v[i]]++;
}
for(auto i:mp)
{
v[++tot]=i.first,sm[tot]=i.second;
}
for(register int i=2;i<=kk;i++)
{
fct=(li)fct*i%MOD;
}
for(register int s=0;s<(1<<c);s++)
{
for(register int i=1;i<=tot;i++)
{
d=0;
for(register int j=0;j<=kk;j++)
{
d|=((popc(s&v[i][j])&1)<<j);
}
!cnt[d]?st[++tp]=d:1,cnt[d]+=sm[i];
}
memset(tmp,0,sizeof(tmp)),tmp[0]=1;
for(register int i=1;i<=tp;i++)
{
for(register int j=0;j<=kk;j++)
{
tmp2[j]=(st[i]&(1<<j))?MOD-finv[j]:finv[j];
}
ln(kk+1,tmp2,tmp3);
for(register int j=0;j<=kk;j++)
{
tmp3[j]=(li)tmp3[j]*cnt[st[i]]%MOD;
}
exp(kk+1,tmp3,tmp2),memset(tmp4,0,sizeof(tmp4));
for(register int j=0;j<=kk;j++)
{
for(register int k=0;k<=kk-j;k++)
{
tmp4[j+k]+=(li)tmp2[j]*tmp[k];
}
}
for(register int j=0;j<=kk;j++)
{
tmp[j]=tmp4[j]%MOD;
}
cnt[st[i]]=0;
}
tp=0,f[s]=(li)tmp[kk]*fct%MOD;
}
for(register int i=1;i<(1<<c);i<<=1)
{
for(register int p=0;p<(1<<c);p+=i<<1)
{
for(register int j=p;j<p+i;j++)
{
d=f[j],f[j]=(f[j]+f[j+i])%MOD,f[j+i]=(d-f[j+i]+MOD)%MOD;
}
}
}
d=(li)qpow(1<<c,MOD-2)*qpow(n,MOD-1-kk)%MOD;
for(register int i=0;i<(1<<c);i++)
{
printf("%d ",(li)f[i^xorv]*d%MOD);
}
}