烷基计数 加强版 加强版

  • 对多项式求逆有了更深刻的理解,如1-x的逆是1+x
  • 多项式或许可以用向量存储,并重载运算符
  • 如果参与相乘的两多项式的其中一项项数较少,建议直接朴素相乘,使用NTT反而会降低效率导致TLE
  • NTT中step的值需要开一个桶存下来以避免重复计算,否则也会TLE
  • f(\(x^2\))、f(\(x^3\))的值都可以直接计算出来,在牛顿迭代法的求导中视为常数
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
int inv6;
long long f[100005],g[2],h[2000005],h1[2000005],h2[2000005],h3[2000005],m1[2000005],m2[2000005],tmp[2000005],ans[2000005],ntt[2000005],F[2000005],G[2000005];
unordered_map<int,int>q;
void NTT(long long *f,int n,int opt)
{
	if(n==1)
	{
		return;
	}
	for(int i=0;i<n;i++)
	{
		ntt[i]=f[i];
	}
	for(int i=0;i<n;i++)
	{
		if(i%2==0)
		{
			f[i/2]=ntt[i];
		}
		else
		{
			f[i/2+n/2]=ntt[i];
		}
	}
	long long *g=f,*h=f+n/2;
	NTT(g,n/2,opt);
	NTT(h,n/2,opt);
	long long cur=1,step;
	if(opt==1)
	{
		if(q.find(998244352/n)==q.end())
		{
			q[998244352/n]=power(3,998244352/n);
		}
		step=q[998244352/n];
	}
	else
	{
		if(q.find(998244352-998244352/n)==q.end())
		{
			q[998244352-998244352/n]=power(3,998244352-998244352/n);
		}
		step=q[998244352-998244352/n];
	}
	for(int i=0;i<n/2;i++)
	{
		ntt[i]=(g[i]+h[i]*cur%mod)%mod;
		ntt[i+n/2]=(g[i]-h[i]*cur%mod+mod)%mod;
		cur*=step;
		cur%=mod;
	}
	for(int i=0;i<n;i++)
	{
		f[i]=ntt[i];
	}
}
void mul(long long *f,int n,int i1,long long *g,int m,int i2,long long *ans,int &l)
{
	if(n<10||m<10)
	{
		int L=(n-1)*i1+(m-1)*i2+1;
		for(int i=0;i<L;i++)
		{
			tmp[i]=0;
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				tmp[i*i1+j*i2]+=(f[i]*g[j]%mod);
				tmp[i*i1+j*i2]%=mod;
			}
		}
		for(int i=0;i<L;i++)
		{
			ans[i]=tmp[i];
		}
		l=L;
		return;
	}
	for(int i=0;i<n;i++)
	{
		F[i*i1]=f[i];
	}
	n=i1*(n-1)+1;
	for(int i=0;i<m;i++)
	{
		G[i*i2]=g[i];
	}
	m=i2*(m-1)+1;
	int L=n+m-1;
	int r=ceil(log(L)/log(2));
	NTT(F,(1<<r),1);
	NTT(G,(1<<r),1);
	for(int i=0;i<(1<<r);i++)
	{
		F[i]*=G[i];
		F[i]%=mod;
	}
	NTT(F,(1<<r),-1);
	int inv=power((1<<r),998244351);
	for(int i=0;i<L;i++)
	{
		ans[i]=F[i]*inv%mod;
	}
	for(int i=0;i<(1<<r);i++)
	{
		F[i]=G[i]=0;
	}
	l=L;
}
void shuchu(long long *f,int n)
{
	for(int i=0;i<n;i++)
	{
		if(i!=0)
		{
			cout<<'+';
		}
		cout<<f[i];
		if(i!=0)
		{
			cout<<"x^"<<i;
		}
	}
	cout<<endl;
}
void g0(long long *f,int cur,long long *ans,int &l)
{
	int n,len=0;
	mul(f,cur,1,f,cur,1,h,n);
	mul(h,n,1,f,cur,1,h,n);
	mul(h,n,1,g,2,1,h,n);
	for(int i=0;i<n;i++)
	{
		ans[i]+=h[i];
	}
	len=max(len,n);
	mul(f,cur,2,f,cur,1,h,n);
	mul(h,n,1,g,2,1,h,n);
	for(int i=0;i<n;i++)
	{
		ans[i]+=(3*h[i]);
	}
	len=max(len,n);
	mul(f,cur,3,g,2,1,h,n);
	for(int i=0;i<n;i++)
	{
		ans[i]+=(2*h[i]);
	}
	len=max(len,n);
	for(int i=0;i<len;i++)
	{
		ans[i]%=mod;
		ans[i]=ans[i]*inv6%mod;
	}
	ans[0]++;
	for(int i=0;i<cur;i++)
	{
		ans[i]=(ans[i]-f[i]+mod)%mod;
	}
	l=len;
}
void g1(long long *f,int cur,long long *ans,int &l)
{
	int n,len=0;
	mul(f,cur,1,f,cur,1,h,n);
	mul(h,n,1,g,2,1,h,n);
	for(int i=0;i<n;i++)
	{
		ans[i]+=(3*h[i]);
	}
	len=max(len,n);
	mul(f,cur,2,g,2,1,h,n);
	for(int i=0;i<n;i++)
	{
		ans[i]+=(3*h[i]);
	}
	len=max(len,n);
	for(int i=0;i<len;i++)
	{
		ans[i]%=mod;
		ans[i]=ans[i]*inv6%mod;
	}
	ans[0]--;
	l=len;
}
void cl(long long *f,int n)
{
	for(int i=0;i<n;i++)
	{
		f[i]=0;
	}
}
void qiuni(long long n,long long *f0,long long *a)
{
	if(n==1)
	{
		f0[0]=(power(a[0],998244351)+mod)%mod;
		return;
	}
	qiuni((n+1)/2,f0,a);
	int z;
	mul(f0,(n+1)/2,1,f0,(n+1)/2,1,m1,z);
	mul(m1,n,1,a,n,1,m2,z);
	for(int i=(n+1)/2;i<n;i++)
	{
		f0[i]=(-m2[i]+mod)%mod;
	}
	for(int i=0;i<n;i++)
	{
		m1[i]=0;
	}
	for(int i=0;i<n;i++)
	{
		m2[i]=0;
	}
}
void calc(long long *f,int n)
{
	if(n==1)
	{
		f[0]=1;
		return;
	}
	calc(f,(n+1)/2);
	int n1,n2,n3;
	g0(f,(n+1)/2,h1,n1);
	g1(f,(n+1)/2,h2,n2);
	qiuni(n,h3,h2);
	mul(h1,n,1,h3,n,1,ans,n3);
	for(int i=(n+1)/2;i<n;i++)
	{
		f[i]=(-ans[i]+mod)%mod;
	}
	cl(h1,n1);cl(h2,n2);cl(h3,n);cl(ans,n3);
}
int main()
{
	g[0]=0;g[1]=1;
	inv6=power(6,998244351);
	int n;
	cin>>n;
	calc(f,n+1);
	cout<<f[n]<<endl;
	return 0;
}
posted @ 2024-07-11 20:37  D06  阅读(5)  评论(0编辑  收藏  举报