zoukankan      html  css  js  c++  java
  • 【洛谷P5577】【CmdOI2019】算力训练(FWT)

    传送门

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

    显然是做fwtfwt
    由于998244353998244353没有w5,w6w_5,w_6
    手动扩域即可
    考虑加起来做fwtfwt,然后再还原乘起来的fwtfwt点值
    考虑高维dftdft时是一维一维的做
    每一次都是乘wijw^{ij}
    一个位置aabb的贡献是
    waibiw^{sum a_i*b_i}
    由于是(1+xi)(1+x^i)
    所以最后一定是(1+wkp)(1+w_k^p)的形式
    那么如果只把(xai)(x^{a_i})加起来做fwtfwt
    最后一个位置xxfxtf_{x,t}wktw_k^t
    就是说实际是(1+wkt)fx,t(1+w_k^t)^{f_{x,t}}
    全部乘起来在idwtidwt回去即可

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

    #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()<<'
    ';//Add(ret,mul(mul(i,i),f[i].ans()));
    }
    
  • 相关阅读:
    POJ 3687 Labeling Balls <<拓扑排序
    FATFS 初学之 f_mount
    STM8 低功耗时钟管理
    还记得 C中带参宏的 "#"号吗?
    8.9并发编程(一)
    8.8网络编程(三)
    8.7网络编程(二)
    8.6网络编程(一)
    7.30反射、元类及项目生命周期
    7.29多态
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328333.html
Copyright © 2011-2022 走看看