zoukankan      html  css  js  c++  java
  • 【Codeforces 1103E】 Radix sum (FWT)

    传送门

    ldxfAKefAKeldxfAKefAKe的帮助下终于会这道题了

    其实发现本身只是一个十进制fwtfwt裸题
    但是由于奇特的模数2582^{58}没法直接搞

    问题在于没有ω10omega_{10}以及idwtidwt的时候除1010没有逆元

    首先逆元的问题可以发现10=25510=2*5,5有逆元
    然后发现实际上由于模数是二的次方所以直接除以2也是对的

    然后考虑如何处理ω10omega_{10}
    考虑直接对每个数表示为维护一个多项式iaiω10isum_{i}a_iomega_{10}^i
    显然多项式长度只有10
    然后就可以直接做十进制fwtfwt

    最后输出答案的问题
    直接输出常数项肯定是错的
    由于最后答案一定是个整数
    可以考虑ω10=cosπ/5+isinπ/5omega_{10}=cos_{pi/5}+isin_{pi/5}
    然后带进iaiω10isum_ia_iomega_{10}^i
    可以直接把实部的实数系数加起来就是答案
    a0+(a1a2+a3a4a6+a7a8+a9)/4a5a_0+(a_1-a_2+a_3-a_4-a_6+a_7-a_8+a_9)/4-a_5

    中间可以不用取模,用unsigned long longunsigned long long,最后模一次即可

    #include<bits/stdc++.h>
    using namespace std;
    #define cs const
    #define re register
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define ll long long
    #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(){
    	char ch=gc();
    	int res=0;bool f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(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;}
    typedef unsigned long long ull;
    ull tmp[20];
    cs int N=100005;
    int n,mx;
    cs ull inv5=57646075230342349ull;
    cs ull mod=(1ll<<58);
    struct plx{
    	ull a[10];
    	plx(){memset(a,0,sizeof(a));}
    	inline ull &operator [](cs int &k){return a[k];}
    	inline cs ull &operator [](cs int &k)const{return a[k];}
    	friend inline plx operator *(plx a,plx b){
    		for(int i=0;i<10;i++)if(a[i])
    		for(int j=0;j<10;j++)tmp[i+j]+=a[i]*b[j];
    		for(int i=0;i<10;i++)a[i]=tmp[i]+tmp[i+10],tmp[i]=tmp[i+10]=0;
    		return a;
    	}
    	inline ull val(){
    		ull ret=0;
    		ret+=(a[0]-a[5])*4;
    		ret+=a[1]-a[2]+a[3]-a[4]-a[6]+a[7]-a[8]+a[9];
    		return (ret>>2)%mod;
    	}
    }f[N<<1];
    inline plx ksm(plx a,int b){
    	plx ret;ret[0]=1;
    	for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a;
    	return ret;
    }
    inline void fwt(plx *f,int lim,int kd){
    	ull tmp[10][20];
    	for(int mid=1;mid<lim;mid*=10)
    	for(int i=0;i<lim;i+=mid*10)
    	for(int j=0;j<mid;j++){
    		for(int k=0;k<10;k++){
    			memset(tmp[k],0,sizeof(tmp[k]));
    			for(int p=0;p<10;p++){
    				int mt=k*p%10;
    				if(kd==-1)mt=(10-mt)%10;
    				for(int l=0;l<10;l++)tmp[k][l+mt]+=f[i+j+p*mid][l];
    			}
    			for(int l=10;l<20;l++)tmp[k][l-10]+=tmp[k][l];
    		}
    		if(kd==1)for(int k=0;k<10;k++){for(int p=0;p<10;p++)f[i+j+k*mid][p]=tmp[k][p];}
    		else for(int k=0;k<10;k++){for(int p=0;p<10;p++)f[i+j+k*mid][p]=(tmp[k][p]/2)*inv5;}
    	}
    }
    int main(){
    	#ifdef Stargazer
    	freopen("lx.cpp","r",stdin);
    	#endif
    	n=read();
    	for(int i=1;i<=n;i++){
    		int x=read();
    		chemx(mx,x);
    		f[x][0]++;
    	}
    	int lim=1;
    	while(lim<=mx)lim*=10;
    	fwt(f,lim,1);
    	for(int i=0;i<lim;i++)f[i]=ksm(f[i],n);
    	fwt(f,lim,-1);
    	for(int i=0;i<n;i++)cout<<f[i].val()<<'
    ';
    }
    
  • 相关阅读:
    字符串的比较方法---Java
    [模板]二进制枚举
    [唯一分解定理]感谢ZLY讲解
    [数学] 小数点后第n位
    [模板]二维前缀和
    [模板]欧拉函数及其应用
    [51nod] 1024 矩阵中不重复的元素
    Codeforces Round #521 (Div. 3) D. Cutting Out
    [差分] [POJ] 3276 Face The Right Way
    Educational Codeforces Round 54 (Rated for Div. 2) C. Meme Problem
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328337.html
Copyright © 2011-2022 走看看