任意模数fft--HDU4656 Evaluation

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4656

脑子抽了做叉姐200题,一道题上午续到晚上。。

这道题不仅式子贼难推(推了几个小时弃疗),推完还不能直接上fft,要用什么任意模数fft(代码又调几个小时)。。

part1:推式子

任意模数fft--HDU4656 Evaluation_第1张图片

----转载自https://blog.csdn.net/whzzt/article/details/70880091(Orz)

个人认为比较高妙的两步是将枚举顺序交换,然后先处理掉一部分化简式子,还有一步就是(k-j)^2那个吊炸天的操作了(推了上午搞不出来就是因为c^2kj这个玄学东西)。

part2:任意模数fft

之后因为ai在10^6,而且模数不是ntt模数,所以要用什么任意模数fft,强行学了一波,其实是一种解决子问题在合并的思想,将模数拆到根号级别,得到任意一个数可表示为a*k+b形式,把两个要进行卷积的数组中每个数都拆成a,b,一共四个数组,都做一次DFT,然后发现实际上(a1*k+b1)*(a2*k+b2)==a1*a2*k*k+(a1*b2+a2*b1)*k+b1*b1,k是一个常数提到fft过程完成后乘,所以这样按乘k的次数分3组最后合并,就能保证fft时数的大小转变为根号n级,不会爆精度了。。

代码:

#include
#define ll long long
#define db double
using namespace std;
const ll mod=1e6+3,mo=sqrt(mod);
const int N=5e5+10,M=2e5+10;
const db pi=acos(-1);
struct cp{
	db r,i;
	cp(){r=0,i=0;}
	cp(db x,db y):r(x),i(y){}
}omg[N],mp[4][N];
cp operator +(const cp x,const cp y)
{return cp(x.r+y.r,x.i+y.i);}
cp operator -(const cp x,const cp y)
{return cp(x.r-y.r,x.i-y.i);}
cp operator *(const cp x,const cp y)
{return cp(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
int n,wh[N],lim,cnt,tp1[N],tp2[N],tax1[N],tax2[N],tax3[N];
int jc[M],inv[mod+10],ijc[M],bb[M],dd[M],idd[M];
int b,c,d,a[M];
ll p[N],ans[N];
ll qpow(ll x,ll y)
{
	ll res=1;
	while(y)
	{
		if(y&1)res=1LL*res*x%mod;
		x=1LL*x*x%mod,y>>=1;
	}
	return res;
}
void init()
{
	jc[0]=1,ijc[0]=1,inv[1]=1;
	for(int i=2;i>1]>>1)|((i&1)<<(cnt-1));
	for(int i=0;i>1;
		for(int i=0;i

 

你可能感兴趣的:(笔记)