首页 > 其他分享 >分治NTT

分治NTT

时间:2023-02-12 12:14:40浏览次数:39  
标签:return int s2 分治 NTT lim

首先是NTT的板子。

int cnt[N];
void NTT(int a[],int lim,bool type){
	for(int i=0;i<(1<<lim);i++)cnt[i]=(cnt[i>>1]>>1)|((i&1)<<(lim-1));
	for(int i=0;i<(1<<lim);i++)if(i<cnt[i])swap(a[i],a[cnt[i]]);
	for(int i=1;i<(1<<lim);i<<=1){
		int dd=qp(type?3:inv,(mod-1)/i>>1);
		for(int j=0;j<(1<<lim);j+=i<<1){
			int t=1;
			for(int k=0;k<i;k++){
				int x=t*a[i+j+k]%mod;
				a[i+j+k]=(a[j+k]-x+mod)%mod;
				a[j+k]=(a[j+k]+x)%mod;t=t*dd%mod;
			}
		}
	}
	if(type)return;int nowInv=qp(1<<lim,mod-2);
	for(int i=0;i<(1<<lim);i++)a[i]=a[i]*nowInv%mod;
}

然后是分治 NTT。分治 NTT 其实就是一个NTT的板子,然后通过分治的方法(类似cdq分治)来快速计算,复杂度是 \(O(N\log^2N)\),也很好理解。

#include<bits/stdc++.h>
//#define feyn
#define int long long
using namespace std;
const int N=1<<17;
const int mod=998244353;
const int inv=(mod+1)/3;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int qp(int s1,int s2){
	if(s2==1)return s1;int an=qp(s1,s2>>1);
	if(s2&1)return an*an%mod*s1%mod;else return an*an%mod;
}

int cnt[N];
void NTT(int a[],int lim,bool type){
	for(int i=0;i<(1<<lim);i++)cnt[i]=(cnt[i>>1]>>1)|((i&1)<<(lim-1));
	for(int i=0;i<(1<<lim);i++)if(i<cnt[i])swap(a[i],a[cnt[i]]);
	for(int i=1;i<(1<<lim);i<<=1){
		int dd=qp(type?3:inv,(mod-1)/i>>1);
		for(int j=0;j<(1<<lim);j+=i<<1){
			int t=1;
			for(int k=0;k<i;k++){
				int x=t*a[i+j+k]%mod;
				a[i+j+k]=(a[j+k]-x+mod)%mod;
				a[j+k]=(a[j+k]+x)%mod;t=t*dd%mod;
			}
		}
	}
	if(type)return;int nowInv=qp(1<<lim,mod-2);
	for(int i=0;i<(1<<lim);i++)a[i]=a[i]*nowInv%mod;
}

int m,f[N],g[N],a[N],b[N];
void solve(int l,int r,int lim){
	if(lim<=0)return;int mid=(l+r)>>1;
	solve(l,mid,lim-1);
	for(int i=0;i<(1<<lim);i++)a[i]=(l+i<=mid)?f[l+i]:0;
	for(int i=0;i<(1<<lim);i++)b[i]=g[i];
	NTT(a,lim,true);NTT(b,lim,true);
	for(int i=0;i<(1<<lim);i++)a[i]=a[i]*b[i]%mod;
	NTT(a,lim,false);
	for(int i=mid+1;i<=r;i++)f[i]=(f[i]+a[i-l])%mod;
	solve(mid+1,r,lim-1);
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);int n=1;while((1<<n)<m)++n;
	for(int i=1;i<m;i++)read(g[i]);f[0]=1;
	solve(0,(1<<n)-1,n);
	for(int i=0;i<m;i++)printf("%lld ",f[i]);
	
	return 0;
}

然后是两个例题。

P4841

用 \(f_{x}\) 代表大小为 \(x\) 的图的答案,\(g_x\) 代表不要求联通的方案。于是显然有:

\[\begin{aligned} f_{x}&=\sum\limits_{i=1}^{x-1}\binom{x}{i}f_{i}g_{x-i}\\ &=\sum\limits_{i=1}^{x-1}x!\dfrac{f_i}{i!}\dfrac{g_{x-i}}{(x-i)!} \end{aligned} \]

然后就是分治 NTT 的板子了。

标签:return,int,s2,分治,NTT,lim
From: https://www.cnblogs.com/Feyn/p/17113578.html

相关文章

  • QOJ5013 Astral Birth(凸包,分治,堆,贪心)
    QOJ5013AstralBirth\(m=1\)直接求LIS。否则对于\(m\ge2\),就是求把序列分成\(m+1\)段,每段翻转或者不翻转,最终最多\(1\)的个数。很明显相邻两段翻不翻转的......
  • FFT&NTT
    FFT快速傅里叶变换<NTTFFT和NTT是\(O(nlogn)\)处理两个多项式相乘的算法(FFT<NTT)前置知识复数一个复数可以表示为\[z=a+ib~~a,b\inR\]我们把他看做平面上的一个点,......
  • 【YBT2023寒假Day9 B】买棉花糖(DP)(分治)
    买棉花糖题目链接:YBT2023寒假Day9B题目大意有n个商店,每个商店有ci个物品,原价是ai,你在一个商店买的物品越多,下一个买的就越少,每次减少di块钱。然后有q次询问,......
  • currentTimeMillis
    刚刚接触JAVA时,为了便于记录某个方法块的执行时间,通常都会在代码块的执行前和执行后各标记一个时间,取两个时间差。但是初学者一般只会选择用LocalDateTime来标记,然后用Dura......
  • 【YBT2023寒假Day7 B】打怪兽(cdq分治)(斜率优化)
    打怪兽题目链接:YBT2023寒假Day7B题目大意有n个怪,每个怪有攻击力和血量。你每次可以选一个怪打b的伤害,如果一个怪的血量小于等于0就死了。然后每次你打完之后所......
  • 快速傅里叶变换(FFT)的分治实现
    本文作者为JustinRochester。目录地址上一篇下一篇......
  • 算法导论:分治算法
    效率分析迭代法求n!intfact(intn){ if(n<=1)return1;elsereturnn*fact(n-1);}递归关系式:\[T(n)= \begin{cases} 1,&n=1\\ T(n-1)+1,&n>1 ......
  • 算重学(3) 分治
    eg分治FFThttps://www.luogu.com.cn/problem/P4721那我定义solve(l,r)为求出来\([l,r]\),那么考虑先求完左部分,然后考虑左部分对右部分的贡献,这样一定是对的?定义so......
  • 分治法学习笔记
    分治法学习笔记目录分治法学习笔记1,什么是分治法2,什么时候使用分治法3,分治法的解题步骤4,分治法与动态规划的异同5,例题1,什么是分治法字面意思,就是将一个大问题分解为若干......
  • 递归-分治
    递归递归,将问题分解为重叠的子问题,f(n)=f(n-1)+xxx,满足这样的状态转移方程,说明原问题是不是依赖递归子问题,即f(n)依赖f(n-1)确定递归出口递归返回时还原现场78.子......