#FWT#ABC367 G - Sum of (XOR^K or 0)

题目

给定一个长度为 \(n\) 的序列 \(a\),求所有长度为 \(m\) 的倍数的子序列异或和的 \(k\) 次方之和。


分析

首先异或和以及 \(k\) 次方进行分离,应该先求出每种异或和对应的方案数,再赋以 \(k\) 次方。

抽象一点也就是 \(\sum_{i=0}^{2^o-1}[x^iy^0]i^k\prod_{j=1}^n(1+x^{a_j}y)\),其中 \(x\) 是异或卷积,\(y\) 是针对 \(m\) 的循环卷积。

如果直接 \(n\) 个多项式相乘显然不行,观察对于 \(1(x^0)\) 经过 FWT 后为全 \(1\) 的序列,而 \(x^{a_j}\) 经过 FWT 后为 \(\pm 1\) 的序列,

那么进行 FWT 后,后面的式子实际是 \([y^0](1+y)^c(1-y)^{n-c}\),也就转化成求有多少个 \(a_j\) 经过 FWT 变换能在 \(i\) 的位置产生 \(1\)

由于 FWT 的线性性,将 \(a_i\) 对应位置加一得到的 \(f\) 数组进行 FWT 后,\(c-(n-c)=f_i\),那么就能把 \(c\) 解出来。

对于 \(y\) 的卷积可以在 \(O(nm)\) 的时间预处理,那么代入该式子后进行逆 FWT 即可。


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod=998244353,inv=499122177,N=1048576;
int f[N],n,m,k,cnt,mx,ans,mi[N],prime[N],dp[N],g0[N][111],g1[N][111],Cnt; 
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans; 
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
int mo1(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int mo2(int x,int y){return x<y?x-y+mod:x-y;}
void FWT_XOR(int *f,int opt){
	for (int p=2;p<=n;p<<=1){
		int len=p>>1;
		for (int i=0;i<n;i+=p)
		    for (int j=i;j<i+len;++j){
		    	int t1=f[j],t2=f[j+len];
		    	f[j]=mo1(t1,t2),f[j+len]=mo2(t1,t2);
		    	if (opt==-1) f[j]=1ll*f[j]*inv%mod,
		    	    f[j+len]=1ll*f[j+len]*inv%mod;
			}
	}
}
int ksm(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
int main(){
    cnt=iut(),m=iut(),k=iut();
    for (int i=0;i<cnt;++i){
		int x=iut();
		mx=max(mx,x);
		++f[x];
	}
	for (n=1;n<=mx;n<<=1);
    mi[1]=1;
	for (int i=2;i<=n-1;++i){
		if (!mi[i]) mi[i]=ksm(i,k),prime[++Cnt]=i;
		for (int j=1;j<=Cnt&&prime[j]<=(n-1)/i;++j){
			mi[i*prime[j]]=1ll*mi[i]*mi[prime[j]]%mod;
			if (i%prime[j]==0) break;
		}
	}
	FWT_XOR(f,1);
	g0[0][0]=g1[0][0]=1;
	for (int i=1;i<=cnt;++i){
		for (int j=0;j<m;++j){
			g0[i][j==m-1?0:(j+1)]=mo1(g0[i-1][j==m-1?0:(j+1)],g0[i-1][j]);
			g1[i][j==m-1?0:(j+1)]=mo2(g1[i-1][j==m-1?0:(j+1)],g1[i-1][j]);
		}
	}
	for (int i=0;i<=cnt;++i){
		dp[i]=1ll*g0[i][0]*g1[cnt-i][0]%mod;
		for (int j=1;j<m;++j)
		    dp[i]=mo1(dp[i],1ll*g0[i][j]*g1[cnt-i][m-j]%mod);
	}
	for (int i=0;i<n;++i) f[i]=dp[((cnt+f[i])%mod)>>1];
	FWT_XOR(f,-1);
	for (int i=1;i<n;++i) ans=mo1(ans,1ll*mi[i]*f[i]%mod);
	return !printf("%d",ans);
}
posted @ 2024-09-07 01:49  lemondinosaur  阅读(7)  评论(0编辑  收藏  举报