1. 程式人生 > 其它 >luogu P4091 [HEOI2016/TJOI2016]求和

luogu P4091 [HEOI2016/TJOI2016]求和

題面傳送門
並不覺得這道題有黑題難度。
首先因為當\(j>i\)\(S(i,j)=0\)所以這個東西其實可以寫成\(\sum\limits_{j=0}^{n}{j!\times 2^j\sum\limits_{i=0}^{n}{S(i,j)}}\)
我們設\(H(j)=\sum\limits_{i=0}^{n}{S(i,j)}\)就可以\(O(n)\)算這個式子的值了。
上面那個式子我們考慮用第二類斯特林數的通項公式變成\(\sum\limits_{i=0}^{n}{\sum\limits_{k=0}^{j}{\frac{(-1)^k(j-k)^i}{k!(j-k)!}}}\)
交換求和順序變成\(\sum\limits_{k=0}^{j}{\frac{(-1)^k}{k!(j-k)!}\sum\limits_{i=0}^{n}{(j-k)^i}}\)


\(F(x)=\sum\limits_{i=0}^{n}{x^i}\)這個顯然可以等比數列\(O(1)\)求。
那麼原式就變成\(\sum\limits_{k=0}^{j}{\frac{(-1)^k}{k!(j-k)}F(j-k)}\)
然後顯然卷一下就可以\(O(nlogn)\)求了。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 300000
#define M 200000
#define mod 998244353
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,tr[N+5];ll F[N+5],G[N+5],Ans,invn,ToT=1,frc[N+5],H[N+5],inv[N+5];
I ll mpow(ll x,int y=mod-2){ll ans=1;while(y) (y&1)&&(ans=ans*x%mod),y>>=1,x=x*x%mod;return ans;}const ll Gs=3,invG=mpow(Gs);
I void swap(ll &x,ll &y){x^=y^=x^=y;}
I void NTT(ll *A,int n,int flag){
	int i,j,h;ll now,key,pus;for(i=0;i<n;i++) i<tr[i]&&(swap(A[i],A[tr[i]]),0);
	for(i=2;i<=n;i<<=1){
		for(key=mpow(flag?Gs:invG,(mod-1)/i),j=0;j<n;j+=i){
			for(now=1,h=j;h<j+i/2;h++)pus=now*A[h+i/2]%mod,A[h+i/2]=(A[h]-pus+mod)%mod,A[h]=(A[h]+pus)%mod,now=now*key%mod;
		}
	}
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d",&n);frc[0]=inv[0]=1;for(i=1;i<=n;i++) frc[i]=frc[i-1]*i%mod,inv[i]=mpow(frc[i]);
	for(i=0;i<=n;i++)F[i]=(i&1)?(mod-inv[i]):(inv[i]);H[0]=1;H[1]=n+1;for(i=2;i<=n;i++) H[i]=(mpow(i,n+1)-1)*mpow(i-1)%mod;
	for(i=0;i<=n;i++) G[i]=H[i]*inv[i]%mod;for(m=1;m<=n*2;m<<=1);for(i=0;i<m;i++)tr[i]=(tr[i>>1]>>1)|((i&1)?(m>>1):0);
	NTT(F,m,1);NTT(G,m,1);for(i=0;i<m;i++)F[i]=F[i]*G[i]%mod;NTT(F,m,0);
	for(i=0;i<=n;i++) Ans+=ToT*frc[i]%mod*F[i]%mod,ToT=ToT*2%mod;printf("%lld\n",Ans%mod*mpow(m)%mod);
}