【Codeforces 1103E】 Radix sum (FWT)

传送门

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

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

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

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

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

最后输出答案的问题
直接输出常数项肯定是错的
由于最后答案一定是个整数
可以考虑ω10=cosπ/5+isinπ/5\omega_{10}=\cos_{\pi/5}+i\sin_{\pi/5}
然后带进iaiω10i\sum_ia_i\omega_{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()<<'\n';
}
发布了581 篇原创文章 · 获赞 193 · 访问量 5万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览