Codeforces 1103 E. Radix sum(多维傅里叶变换,循环卷积)

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/90294174

题目
可以去这篇博客看题意顺便了解一下基本理论
基本理论

看完基本理论之后就全是细节问题了。
1.有n次单位根可以DFT后做长度为n的循环卷积。
2.多维的把单位根乘起来就行。
3.没有n次单位根?复数精度不够,模意义下,模数居然是个 2 58 2^{58} 如此不友善,那么有一个通法: ( m o d x n 1 ) \pmod{x^n-1} 的意义下的多项式, n n 次单位根为 x x ,这个。。。
好暴力啊,如果不是多维卷积,这个是 O ( n 3 ) O(n^3) 还不如暴力卷。
可以省掉一个2的常数,用它的分圆多项式
Φ n ( x ) = 1 k n , gcd ( k , n ) = 1 ( x exp ( 2 i π k n ) ) . \Phi_n(x) = \prod_{1 \leq k \leq n, \gcd(k, n) = 1} \left( x - \exp\left(\frac{2i \pi k}{n}\right) \right).
如果你想,还可以继续把原式分解因式找有没有 n n 次单位根。。。。。
这题就凑合用分圆多项式做模式吧。(还可以用5的分圆多项式 Φ 5 ( x ) = x 4 + x 3 + x 2 + x + 1 = ( x 5 1 ) / ( x 1 ) \Phi_5(x)= x^4+x^3+x^2+x+1 = (x^5-1)/(x-1) ,然后直接拿 x 5 1 x^5-1 做模式,乘单位根的时候可以直接位移少了一个5的常数,最后再 m o d    Φ 5 ( x ) \mod\Phi_5(x)
4.有没有n的逆元?上面大佬博客讲的很清楚。
5.怎么DFT?分状态像DP一样高维求和就行了。
总结:有了(形式方便运算的)n次单位根就是有了一切。

AC Code:

#include<bits/stdc++.h>
#define ull unsigned long long
#define maxn 100000
#define BASE 10
using namespace std;

struct cplx{
	ull a[5];
	cplx(ull a0=0,ull a1=0,ull a2=0,ull a3=0,ull a4=0){ a[0]=a0,a[1]=a1,a[2]=a2,a[3]=a3,a[4]=a4; }
	cplx operator +(const cplx &B)const{
		cplx ret;
		for(int i=0;i<5;i++) ret.a[i]=a[i]+B.a[i];
		return ret;
	}
	cplx operator -(const cplx &B)const{
		cplx ret;
		for(int i=0;i<5;i++) ret.a[i]=a[i]-B.a[i];
		return ret;
	}
	cplx operator *(const cplx &B)const{
		static ull ar[10];
		memset(ar,0,sizeof ar);
		for(int i=0;i<5;i++) if(a[i])
			for(int j=0;j<5;j++) if(B.a[j])
				ar[(i+j)%5] += a[i] * B.a[j];
		return cplx(ar[0],ar[1],ar[2],ar[3],ar[4]);
	}
	cplx muldwg(int num){
		cplx ret;
		for(int i=0;i<5;i++) ret.a[(num+i)%5] = (num&1)?-a[i]:a[i];		
		return ret;
	}
}a[maxn];

cplx Pow(cplx base,ull k){
	cplx ret=cplx(1,0,0,0,0);
	for(;k;k>>=1,base=base*base)
		if(k&1)
			ret=ret*base;
	return ret;
}


ull Pow(ull base,ull k){
	ull ret;
	for(;k;k>>=1,base=base*base)
		if(k&1)
			ret=ret*base;
	return ret;
}

int n;

void DFT(cplx *A,int tp){
	int res = (tp == 1 ? 1 : BASE-1);
	for(int L=1;L<maxn;L*=BASE)
		for(int offset=0;offset<maxn;offset++)
			if(offset/L%BASE==0){
				cplx tmp[BASE];
				for(int i=0;i<BASE;i++)
					for(int j=0;j<BASE;j++)
						tmp[i] = tmp[i] + (a[offset+j*L].muldwg(i*j*res%BASE));
				for(int i=0;i<BASE;i++)
					a[offset+i*L]=tmp[i];
			}
}

int main(){
	cout<<(1ull<<63)*2<<endl;
	cin>>n;
	for(int i=0;i<n;i++){
		int x;cin>>x;
		a[x].a[0]++;
	}
	DFT(a,1);
	for(int i=0;i<maxn;i++){
		a[i] = Pow(a[i],n);
	}
	DFT(a,-1);
	
	ull inv5 = 6723469279985657373ULL;
	for(int i=0;i<n;i++){
		ull tmp = (a[i].a[0] - a[i].a[4]) * inv5 / 32ull % (1ull<<58);
		cout<<tmp<<endl;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/90294174
今日推荐