洛谷P4091 [HEOI2016/TJOI2016]求和(NTT+第二類斯特林數)


i=0nj=0nS(i,j)×2j×(j!)\sum_{i=0}^{n}\sum_{j=0}^{n}S(i,j)\times2^j\times(j!)
emmm,顯然後面兩個只帶j的跟i沒啥關係,扔到前面去
j=0n2j×(j!)i=0nS(i,j)\sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}S(i,j)
根據第二類斯特林數的通項公式
S(i,j)=1j!k=0j(1)k(jk)(jk)iS(i,j)=\frac{1}{j!}\sum_{k=0}^{j}(-1)^k{j\choose k}(j-k)^i
展開後面的
j=0n2j×(j!)i=0nS(i,j)\sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}S(i,j)
=j=0n2j×(j!)i=0n1j!k=0j(1)k(jk)(jk)i=\sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}\frac{1}{j!}\sum_{k=0}^{j}(-1)^k{j\choose k}(j-k)^i
=j=0n2j×(j!)i=0n1j!k=0j(1)kj!k!(jk)!(jk)i=\sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}\frac{1}{j!}\sum_{k=0}^{j}(-1)^k\frac{j!}{k!(j-k)!}(j-k)^i
=j=0n2j×(j!)i=0nk=0j(1)k1k!(jk)!(jk)i=\sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}\sum_{k=0}^{j}(-1)^k\frac{1}{k!(j-k)!}(j-k)^i
=j=0n2j×(j!)i=0nk=0j(1)kk!(jk)i(jk)!=\sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{(j-k)^i}{(j-k)!}
發現又有和只帶k和i沒啥關係的式子了,提出來
=j=0n2j×(j!)k=0j(1)kk!i=0n(jk)i(jk)!=\sum_{j=0}^{n}2^j\times(j!)\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{\sum_{i=0}^{n}(j-k)^i}{(j-k)!}
後面那東西有點像卷積啊,看看卷哪兩個函數吧
f(i)=(1)ii!f(i)=\frac{(-1)^i}{i!}
g(i)=j=0niji!=i(n+1)1(i1)i!g(i)=\frac{\sum_{j=0}^{n}i^j}{i!}=\frac{i^{(n+1)}-1}{(i-1)i!}
這兩個都是可以在合法複雜度內遞推的,那麼直接NTT就可以啦

代碼如下:

#include<bits/stdc++.h>
#define mod 998244353
#define g 3
using namespace std;

long long fac[400030],inv[400030],x[400030],y[400030],m2[400030];
int n,lim=1,r[400030],cnt;

long long kasumi(long long a,long long b)
{
	long long ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}

void init()
{
	fac[0]=1;
	for(int i=1;i<=150000;i++)
	{
		fac[i]=fac[i-1]*i%mod;
	}
	inv[150000]=kasumi(fac[150000],mod-2);
	for(int i=149999;i>=0;i--)
	{
		inv[i]=inv[i+1]*(i+1)%mod;
	}
}

long long NTT(long long *a,long long kd)
{
	for(long long i=0;i<lim;i++)
	{
		if(i<r[i])
		{
			swap(a[i],a[r[i]]);
		}
	}
	for(int mid=1;mid<lim;mid<<=1)
	{
		long long wn=kasumi(g,(mod-1)/(mid<<1));
		if(kd) wn=kasumi(wn,mod-2);
		for(int i=0;i<lim;i+=mid*2)
		{
			long long w=1;
			for(int j=0;j<mid;j++,w=w*wn%mod)
			{
				long long gg1=a[i+j];
				long long gg2=a[i+j+mid];
				a[i+j]=(gg1+gg2*w%mod)%mod;
				a[i+j+mid]=(gg1-gg2*w%mod+mod)%mod;
			}
		}
	}
	if(kd)
	{
		long long invl=kasumi(lim,mod-2);
		for(long long i=0;i<lim;i++)
		{
			a[i]=a[i]*invl%mod;
		}
	}
}

int main()
{
	init();
	scanf("%d",&n);
	while(lim<=2*n) lim<<=1,cnt++;
	for(int i=0;i<lim;i++)
	{
		r[i]=(r[i>>1]>>1)|((i&1)<<(cnt-1));
	}
	x[0]=1;x[1]=(-inv[1]+mod)%mod;
	y[0]=1;y[1]=n+1;
	m2[0]=1;m2[1]=2;
	for(int i=2;i<=n;i++)
	{
		x[i]=(i&1)?-inv[i]:inv[i];
		x[i]=(x[i]+mod)%mod;
		y[i]=(kasumi(i,n+1)-1+mod)*kasumi(i-1,mod-2)%mod*inv[i]%mod;
		m2[i]=m2[i-1]*2%mod;
	}
	NTT(x,0);
	NTT(y,0);
	for(int i=0;i<lim;i++)
	{
		x[i]=x[i]*y[i]%mod;
	}
	NTT(x,1);
	long long ans=0;
	for(int i=0;i<=n;i++)
	{
		ans+=m2[i]*fac[i]%mod*x[i]%mod;
		ans%=mod;
	}
	printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章