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


i = 0 n j = 0 n S ( i , j ) × 2 j × ( j ! ) \sum_{i=0}^{n}\sum_{j=0}^{n}S(i,j)\times2^j\times(j!)
emmm,显然后面两个只带j的跟i没啥关系,扔到前面去
j = 0 n 2 j × ( j ! ) i = 0 n S ( i , j ) \sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}S(i,j)
根据第二类斯特林数的通项公式
S ( i , j ) = 1 j ! k = 0 j ( 1 ) k ( j k ) ( j k ) i S(i,j)=\frac{1}{j!}\sum_{k=0}^{j}(-1)^k{j\choose k}(j-k)^i
展开后面的
j = 0 n 2 j × ( j ! ) i = 0 n S ( i , j ) \sum_{j=0}^{n}2^j\times(j!)\sum_{i=0}^{n}S(i,j)
= j = 0 n 2 j × ( j ! ) i = 0 n 1 j ! k = 0 j ( 1 ) k ( j k ) ( j k ) 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 = 0 n 2 j × ( j ! ) i = 0 n 1 j ! k = 0 j ( 1 ) k j ! k ! ( j k ) ! ( j k ) 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 = 0 n 2 j × ( j ! ) i = 0 n k = 0 j ( 1 ) k 1 k ! ( j k ) ! ( j k ) 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 = 0 n 2 j × ( j ! ) i = 0 n k = 0 j ( 1 ) k k ! ( j k ) i ( j k ) ! =\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 = 0 n 2 j × ( j ! ) k = 0 j ( 1 ) k k ! i = 0 n ( j k ) i ( j k ) ! =\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 ) i i ! f(i)=\frac{(-1)^i}{i!}
g ( i ) = j = 0 n i j i ! = i ( n + 1 ) 1 ( i 1 ) 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);
}

猜你喜欢

转载自blog.csdn.net/qq_21829533/article/details/88119232