【洛谷P5577】【CmdOI2019】算力训练(FWT)
首先把权值化作下标
首先显然是要求一样的东西
这里的乘法是进制不进位加法卷积
显然是做
由于没有
手动扩域即可
考虑加起来做,然后再还原乘起来的点值
考虑高维时是一维一维的做
每一次都是乘
一个位置对的贡献是
由于是
所以最后一定是的形式
那么如果只把加起来做
最后一个位置有个
就是说实际是
全部乘起来在回去即可
不用光速幂跑不过去。。。
#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()));
}