把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4245 【模板】任意模数多项式乘法

题面传送门
不得不说这题是真的暴力。
我们发现这个东西不是NTT模数很难搞怎么办呢?
我们联想到万能的FFT,这个东西不需要模数。
但是中间不能取膜,实际上答案会大于longlong
那么我们可以把它拆开。拆成\(a\times 2^{15}+b\)的形式就可以做了。
然后我们其实要求这个东西\(a_1b_1\times 2^{30}+(a_1b_2+a_2b_1)\times 2^{15}+a_2b_2\)发现要\(12\)次NTT不太可行。
然而仔细一想只要\(8\)次因为有重复算的。
然后再一想发现只要\(7\)次因为中间那个在点值乘法时可以直接用。
code:

#include<cstdio>
#include<cmath>
#define I inline
#define lb long double
#define N 300039
#define re register
#define ll long long
using namespace std;
int n,m,k,x,y,z,p,a[N],b[N],tr[N];ll ans[N];
const lb pi=acos(-1);const int w=(1<<15);
struct fs{
	lb a,b;
	fs operator +(const fs &x)const{return (fs){a+x.a,b+x.b};}
	fs operator -(const fs &x)const{return (fs){a-x.a,b-x.b};}
	fs operator *(const fs &x)const{return (fs){a*x.a-b*x.b,a*x.b+b*x.a};}
}f1[N],f2[N],g1[N],g2[N],g3[N];
I void swap(fs &a,fs &b){fs tmp=a;a=b;b=tmp;}
I void fft(fs *f,int m,int flag){
    int i,j,k;fs now,pus,key;
	for(i=0;i<m;i++) (i<tr[i])&&(swap(f[i],f[tr[i]]),0);
	for(i=2;i<=m;i<<=1){
		for(key=(fs){cos(2*pi/i),flag*sin(2*pi/i)},j=0;j<m;j+=i){
			for(now=(fs){1,0},k=j;k<j+i/2;k++) pus=f[k+i/2]*now,f[k+i/2]=f[k]-pus,f[k]=f[k]+pus,now=now*key;
		}
	}
}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d%d%d",&n,&m,&p);
	for(k=1;k<=m+n;k<<=1);for(i=0;i<k;i++)tr[i]=(tr[i>>1]>>1)|((i&1)?k/2:0);
	for(i=0;i<=n;i++) scanf("%d",&a[i]);
	for(i=0;i<=m;i++) scanf("%d",&b[i]);
	for(i=0;i<=n;i++) f1[i]=(fs){(int)(a[i]/w),0},f2[i]=(fs){a[i]%w,0};
	for(i=0;i<=m;i++) g1[i]=(fs){(int)(b[i]/w),0},g2[i]=(fs){b[i]%w,0};
	fft(f1,k,1);fft(f2,k,1);fft(g1,k,1);fft(g2,k,1);
	for(i=0;i<k;i++) g3[i]=g2[i]*f2[i],g2[i]=g2[i]*f1[i]+g1[i]*f2[i],g1[i]=g1[i]*f1[i];
	fft(g1,k,-1);fft(g2,k,-1);fft(g3,k,-1);for(i=0;i<=n+m;i++) g1[i].a=(ll)(g1[i].a/k+0.49),g2[i].a=(ll)(g2[i].a/k+0.49),g3[i].a=(ll)(g3[i].a/k+0.49);
	for(i=0;i<=n+m;i++)printf("%lld ",((ll)((ll)(g1[i].a*w+g2[i].a)%p*w+g3[i].a+p)%p+p)%p);  
}
posted @ 2021-04-03 16:03  275307894a  阅读(53)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end