BZOJ 4555:[TJOI2016&HEOI2016]求和(第二类斯特林数+NTT)

题目链接


\(Description\)

\[\sum_{i=0}^n\sum_{j=0}^iS(i,j)2^jj! \]

对998244353取模后的结果。

\(n<=10^5\)


\(Solution\)
\(S(i,j)\)在这里就非常碍事,怎么把它写成一个多项式的形式呢?

第二类斯特林数还有一种容斥的写法

\[S(n,m)=\frac{1}{m!}\sum_{i=0}^m(-1)^iC_m^i(m-i)^n \]

把它带到要求的式子里去

\[\sum_{i=0}^n\sum_{j=0}^i2^jj!\frac{1}{j!}\sum_{k=0}^j(-1)^k\frac{j!}{k!(j-k)!}(j-k)^i \]

\[=\sum_{j=0}^n2^jj!\sum_{k=0}^j\frac{(-1)^k}{k!}\frac{\sum_{i=0}^n(j-k)^i}{(j-k)!} \]

最后是个等比数列求和

\[\sum_{j=0}^n2^jj!\sum_{k=0}^j\frac{(-1)^k}{k!}\frac{(j-k)^{n+1}-1}{(j-k-1)(j-k)!} \]

后边的求和直接\(NTT\)做。

#include<complex>
#include<cstdio>
using namespace std;
const int mod=998244353,R=3;
const int N=3e5+7;
int n,invR;
int F[N],G[N],fac[N],finv[N],r[N];
int qread()
{
	int x=0;
	char ch=getchar();
	while(ch<'0' || ch>'9')ch=getchar();
	while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
int Fpow(long long b,int p)
{
	long long res=1;
	for(;p;p>>=1,b=b*b%mod)
		if(p&1)res=res*b%mod;
	return res;
}
void NTT(int *a,int lim,int opt)
{
	for(int i=1;i<lim;i++)
		if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=2;i<=lim;i<<=1)
	{
		int mid=i>>1,Wn=Fpow(~opt?R:invR,(mod-1)/i),t;
		for(int j=0;j<lim;j+=i)
		{
			long long w=1;
			for(int k=j;k<j+mid;k++,w=w*Wn%mod)
			{
				t=1ll*w*a[k+mid]%mod;
				a[k+mid]=(a[k]-t+mod)%mod;a[k]=(a[k]+t)%mod;
			}
		}
	}
	if(opt==-1)for(int i=0,inv=Fpow(lim,mod-2);i<lim;i++)a[i]=1ll*a[i]*inv%mod;
}
int main()
{
	scanf("%d",&n);
	fac[0]=finv[0]=1;
	for(int i=1;i<=n;i++)
		fac[i]=1ll*fac[i-1]*i%mod;
	finv[n]=Fpow(fac[n],mod-2);
	for(int i=n-1;i;i--)
		finv[i]=1ll*finv[i+1]*(i+1)%mod;
	for(int i=2;i<=n;i++)
		F[i]=1ll*(Fpow(i,n+1)-1)*Fpow(i-1,mod-2)%mod*finv[i]%mod;
	F[0]=1;F[1]=n+1;
	for(int i=0;i<=n;i++)
		G[i]=((i&1?-1:1)*finv[i]+mod)%mod;
	int lim=1,l=-1;
	invR=Fpow(R,mod-2);
	while(lim<=n+n)lim<<=1,l++;
	for(int i=1;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<l);
	NTT(F,lim,1);NTT(G,lim,1);
	for(int i=0;i<lim;i++)
		F[i]=1ll*F[i]*G[i]%mod;
	NTT(F,lim,-1);
	int ans=0;
	for(int i=0,p=1;i<=n;i++,p=(p<<1)%mod)
		ans=(ans+1ll*p*fac[i]%mod*F[i]%mod)%mod;
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-02-24 10:36  LeTri  阅读(179)  评论(0编辑  收藏  举报