【Codeforces 1103E】 Radix sum (FWT)

传送门

l d x f A K e f A K e ldxfAKefAKe ldxfAKefAKe的帮助下终于会这道题了

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

问题在于没有 ω 10 \omega_{10} ω10以及 i d w t idwt idwt的时候除 10 10 10没有逆元

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

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

最后输出答案的问题
直接输出常数项肯定是错的
由于最后答案一定是个整数
可以考虑 ω 10 = cos ⁡ π / 5 + i sin ⁡ π / 5 \omega_{10}=\cos_{\pi/5}+i\sin_{\pi/5} ω10=cosπ/5+isinπ/5
然后带进 ∑ i a i ω 10 i \sum_ia_i\omega_{10}^i iaiω10i
可以直接把实部的实数系数加起来就是答案
a 0 + ( a 1 − a 2 + a 3 − a 4 − a 6 + a 7 − a 8 + a 9 ) / 4 − a 5 a_0+(a_1-a_2+a_3-a_4-a_6+a_7-a_8+a_9)/4-a_5 a0+(a1a2+a3a4a6+a7a8+a9)/4a5

中间可以不用取模,用 u n s i g n e d   l o n g   l o n g unsigned\ long\ long unsigned 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';
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值