FFT(划掉)NTT模板

UPD : 18/3/13

这是你从未见过的全新版本,常数优秀(相信我),简单好用,背一下用一年

以后还会更新exp,ln之类的

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define rep(a,b,c) for (int a=b;a<=c;a++)
#define per(a,b,c) for (int a=b;a>=c;a--)
#define go(u) for (int o=ft[u],v;v=E[o].t;o=E[o].n)
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef double dob;
typedef pair<int,int> par;
const int N=300010,P=1005060097,g=5,ig=(P*2+1)/5;
LL pw(LL x,LL k){
	LL y=1;
	while (k){
		if (k&1) y=y*x%P;
		x=x*x%P;
		k>>=1;
	}
	return y;
}
namespace po{
	LL a[N],b[N],c[N];
	void dft(LL* a,int n,int op){
		static LL r[N];
		r[0]=0;
		for (int i=0;i<n;i+=2){
			r[i]=r[i>>1]>>1;
			r[i+1]=r[i]|n>>1;
		}
		for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);	
		for (int h=2;h<=n;h<<=1){
			LL wn=pw(op==1?g:ig,(P-1)/h);
			for (int i=0;i<n;i+=h){
				LL w=1;
				for (int j=i;j<i+h/2;j++){
					LL x=a[j],y=a[j+h/2];
					a[j]=(x+y*w)%P;
					a[j+h/2]=(x-y*w)%P;
					w=w*wn%P;
				}
			}
		}
		if (op==-1) for (int i=0,iv=pw(n,P-2);i<n;i++) a[i]=a[i]*iv%P;
	}
	void mul(LL* _a,LL* _b,LL* _c,int len){
		memcpy(a,_a,len*8);
		memcpy(b,_b,len*8);
		dft(a,len,1),dft(b,len,1);
		rep(i,0,len-1) c[i]=a[i]*b[i]%P;
		dft(c,len,-1);
		memcpy(_c,c,len*8);
	}
	void inv(LL* _b,LL* _a,int len){
		int nw=2;
		_b[0]=pw(_a[0],P-2);
		while (nw<=len){
			memcpy(b,_b,nw*8);
			memset(b+nw,0,nw*8);
			memcpy(a,_a,nw*8);
			memset(a+nw,0,nw*8);
			po::dft(b,nw*2,1);
			po::dft(a,nw*2,1);
			for (int i=0;i<nw*2;i++) b[i]=b[i]*(2-a[i]*b[i]%P)%P;
			po::dft(b,nw*2,-1);
			for (int i=0;i<nw;i++) _b[i]=b[i];
			nw<<=1;
		}
	}
};
struct poly{
	int l;
	vector <LL> a;
	LL& operator [](int k){return a[k];}
	void set(int len){
		while (a.size()<len) a.push_back(0);
		while (l>len) a[--l]=0;
		l=len;
	}
	void operator *=(poly k){
		int len=1;
		while (len<l+k.l-1) len<<=1;
		set(len),k.set(len);
		po::mul(&a[0],&k[0],&a[0],len);
	}
	void operator /=(poly k){
		if (k[0]==0){puts("no inv");return;}
		int len=1;
		while (len<k.l) len<<=1;
		set(0),set(len),k.set(len);
		po::inv(&a[0],&k[0],len);
	}
}p1,p2;
int n,m,a[N];
int main(){
	scanf("%d%d",&n,&m);
	rep(i,1,m) scanf("%d",a+i);
	p2.set(n+1);
	rep(i,1,m) if (a[i]<=n) --p2[a[i]];
	++p2[0];// p2 = 1-f(x)
	p1/=p2; 
	printf("%lld\n",(p1[n]+P)%P);
	return 0;
}

=====================================


#include<iostream>
using namespace std;
#define F f[tp]
#define G f[tp^1]
#define X x*m+y
#define Y x*m*2+y
#define MXN 1048576
#define md 1004535809
typedef long long ll;
ll N,tp,i,j,inv,A[MXN],B[MXN],f[2][MXN],w[MXN];
string s;
int n,m,x,y;
void DFT(){
	for (tp=0,n=N,m=1;m<N;n>>=1,m<<=1,tp^=1)
		for (x=0;x*2<n;x++) for (y=0;y<m;y++)
			G[Y]=(F[X]+F[X+N/2]*w[y*n/2])%md,
			G[Y+m]=(F[X]-F[X+N/2]*w[y*n/2])%md;
}
ll pw(ll x,ll k){
	ll t=1;
	for (;k;k>>=1,x=x*x%md)
		if (k&1) t=t*x%md;
	return t;
}
int main(){
	N=1048576;
	cin>>s;
	for (i=tp=0,j=s.size();i<N&&j!=0;) F[i++]=s[--j]-'0';
	for (;i<N;) F[i++]=0;
	for (w[0]=1,w[1]=pw(3,(md-1)/N),i=2;i<N;i++)
		w[i]=w[i-1]*w[1]%md;
	DFT();
	for (i=0;i<N;i++) A[i]=F[i];
	cin>>s;
	for (i=tp=0,j=s.size();i<N&&j!=0;) F[i++]=s[--j]-'0';
	for (;i<N;) F[i++]=0;
	DFT();
	for (i=0;i<N;i++) B[i]=F[i];
	for (i=tp=0;i<N;i++) F[i]=A[i]*B[i]%md;
	for (w[0]=1,w[1]=w[N-1],i=2;i<N;i++)
		w[i]=w[i-1]*w[1]%md;
	DFT();
	inv=pw(N,md-2);
	for (i=N-1;i>-1;i--) F[i]=(F[i]*inv%md+md)%md;
	for (i=j=0;i<N;i++) F[i]+=j,j=F[i]/10,F[i]=F[i]%10;
	while (F[N-1]==0) N--;
	for (i=N-1;i>-1;i--) cout<<F[i];
	return 0;
}


UPD:修改了一些,更好背一点

void DFT(LL *a,int n,LL w0){
	LL i,j,k=0;
	for (i=w[0]=1;i<n;i++) w[i]=w[i-1]*w0%P;
	for (i=0;i<n;i++) f[i]=a[i];
	for (;i;k++,swap(f,g)) for (i=0;i<n>>k+1;i++) for (j=0;j<1<<k;j++)
		g[i<<k+1|j]		=(f[i<<k|j]+f[i<<k|j|n>>1]*w[j*n>>k+1])%P,
		g[i<<k+1|j|1<<k]=(f[i<<k|j]-f[i<<k|j|n>>1]*w[j*n>>k+1])%P;
	for (i=0;i<n;i++) a[i]=g[i];
}

UPD:常数更小的写法, 强大学弟的blog

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值