【洛谷P5577】【CmdOI2019】算力训练(FWT)

传送门

首先把权值化作下标
首先显然是要求 ∏ ( 1 + x a i ) \prod(1+x^{a_i}) (1+xai)一样的东西
这里的乘法是 k k k进制不进位加法卷积

显然是做 f w t fwt fwt
由于 998244353 998244353 998244353没有 w 5 , w 6 w_5,w_6 w5,w6
手动扩域即可
考虑加起来做 f w t fwt fwt,然后再还原乘起来的 f w t fwt fwt点值
考虑高维 d f t dft dft时是一维一维的做
每一次都是乘 w i j w^{ij} wij
一个位置 a a a b b b的贡献是
w ∑ a i ∗ b i w^{\sum a_i*b_i} waibi
由于是 ( 1 + x i ) (1+x^i) (1+xi)
所以最后一定是 ( 1 + w k p ) (1+w_k^p) (1+wkp)的形式
那么如果只把 ( x a i ) (x^{a_i}) (xai)加起来做 f w t fwt fwt
最后一个位置 x x x f x , t f_{x,t} fxt w k t w_k^t wkt
就是说实际是 ( 1 + w k t ) f x , t (1+w_k^t)^{f_{x,t}} (1+wkt)fx,t
全部乘起来在 i d w t idwt idwt回去即可

不用光速幂跑不过去。。。

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define ll long long
#define se second
#define bg begin
cs int RLEN=(1<<20)+1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(int bas=10){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=res*bas+(ch^48),ch=gc();
	return f?res:-res;
}
template<class tp>inline void chemx(tp&a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp&a,tp b){a>b?a=b:0;}
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b,a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(int x){return (x<0)?(x+mod):x;}
int tmp[12],k,n,m,lim;
cs int N=80000;
struct plx{
	int a[6];
	plx(){a[0]=a[1]=a[2]=a[3]=a[4]=a[5]=0;}
	inline int &operator [](cs int &i){return a[i];}
	inline cs int &operator [](cs int &i)cs{return a[i];}
	friend inline plx operator +(plx a,plx b){
		for(int i=0;i<k;i++)Add(a[i],b[i]);
		return a;
	}
	friend inline plx operator -(plx a,plx b){
		for(int i=0;i<k;i++)Dec(a[i],b[i]);
		return a;
	}
	friend inline plx operator *(plx a,plx b){
		for(int i=0;i<k;i++)if(a[i])for(int j=0;j<k;j++)
		Add(tmp[i+j],mul(a[i],b[j]));
		for(int i=0;i<k;i++)a[i]=add(tmp[i],tmp[i+k]),tmp[i]=tmp[i+k]=0;
		return a;
	}
	inline int ans(){
		if(k==5)return dec(a[0],a[1]);
		else return add(dec(a[0],a[3]),mul(dec(add(a[1],a[5]),add(a[2],a[4])),Inv(2)));
	}
}tp[6],f[N],w[6],pw1[6][1001],pw2[6][1001],I;
inline void init_w(){
	for(int i=0;i<k;i++)w[i][i]=1;
	for(int i=0;i<k;i++){
		pw1[i][0]=pw2[i][0]=w[0];
		pw1[i][1]=I+w[i];
		for(int j=2;j<=1000;j++)pw1[i][j]=pw1[i][j-1]*pw1[i][1];
		pw2[i][1]=pw1[i][1000];
		for(int j=2;j<=1000;j++)pw2[i][j]=pw2[i][j-1]*pw2[i][1];
	}
}
inline void dwt(plx *f,int lim){
	for(int mid=1;mid<lim;mid*=k)
	for(int i=0;i<lim;i+=mid*k)
	for(int j=0;j<mid;j++){
		for(int l=0;l<k;l++)tp[l]=f[i+l*mid+j];
		for(int p=0;p<k;p++){
			int ps=i+p*mid+j;
			f[ps]=plx();
			for(int l=0;l<k;l++)
				f[ps]=f[ps]+w[l*p%k]*tp[l];
		}
	}
}
inline void idwt(plx *f,int lim){
	for(int mid=1;mid<lim;mid*=k)
	for(int i=0;i<lim;i+=mid*k)
	for(int j=0;j<mid;j++){
		for(int l=0;l<k;l++)tp[l]=f[i+l*mid+j];
		for(int p=0;p<k;p++){
			int ps=i+p*mid+j;
			f[ps]=plx();
			for(int l=0,o;l<k;l++)
				o=l*p%k,f[ps]=f[ps]+w[o?(k-o):0]*tp[l];
		}
	}
	for(int i=0,iv=Inv(lim);i<lim;i++)
	for(int j=0;j<k;j++)Mul(f[i][j],iv);
}
inline plx pksm(plx a,int b){
	plx ret=I;
	for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a;
	return ret;
}
inline plx get(plx x){
	plx ret=I;
	for(int i=0;i<k;i++){
		ret=ret*pw1[i][x[i]%1000]*pw2[i][x[i]/1000];
	}
	return ret;
}
int main(){
	#ifdef Stargazer
	freopen("lx.cpp","r",stdin);
	freopen("my.out","w",stdout);
	#endif
	n=read(),k=read(),m=read();
	I[0]=1,lim=ksm(k,m),init_w();
	for(int i=1;i<=n;i++)f[read(k)][0]++;
	dwt(f,lim);
	for(int i=0;i<lim;i++)f[i]=get(f[i]);
	idwt(f,lim);int ret=0;
	for(int i=0;i<lim;i++)cout<<f[i].ans()<<'\n';//Add(ret,mul(mul(i,i),f[i].ans()));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值