【TJOI/HEOI2016】【洛谷P4901】【LOJ2058】【BZOJ4555】求和(生成函数)

传送门


题解:

现在拿到洛谷rank1,BZOJrank1,LOJrank1。

首先这道题可以多项式求逆或者直接卷积做,复杂度都是 O ( n log ⁡ n ) O(n\log n) O(nlogn)

先推式子,根据第二类斯特林数通项公式: S n , k = ∑ i = 0 k ( − 1 ) i ( k − i ) n i ! ( k − i ) ! S_{n,k}=\sum_{i=0}^k\frac{(-1)^i(k-i)^n}{i!(k-i)!} Sn,k=i=0ki!(ki)!(1)i(ki)n,直接代入可以得到:

A n s = ∑ i = 0 n ∑ j = 0 n 2 j j ! S i , j = ∑ i = 0 n ∑ j = 0 i 2 j ∑ k = 0 j ( j k ) ( − 1 ) j − k k i = ∑ j = 0 n ∑ k = 0 j ( − 1 ) j − k ( j k ) 2 j k n + 1 − 1 k − 1 = ∑ k = 0 n k n + 1 − 1 k − 1 ∑ j = k n ( − 1 ) j − k ( j k ) 2 j \begin{aligned} Ans=&\sum_{i=0}^n\sum_{j=0}^n2^jj!S_{i,j}\\ =&\sum_{i=0}^n\sum_{j=0}^i2^j\sum_{k=0}^j{j\choose k}(-1)^{j-k}k^i\\ =&\sum_{j=0}^n\sum_{k=0}^j(-1)^{j-k}{j\choose k}2^j\frac{k^{n+1}-1}{k-1}\\ =&\sum_{k=0}^n\frac{k^{n+1}-1}{k-1}\sum_{j=k}^{n}(-1)^{j-k}{j\choose k}2^j \end{aligned} Ans====i=0nj=0n2jj!Si,ji=0nj=0i2jk=0j(kj)(1)jkkij=0nk=0j(1)jk(kj)2jk1kn+11k=0nk1kn+11j=kn(1)jk(kj)2j

到这里很多人就直接做卷积了,但是观察一下这个东西: f ( k ) = ∑ j = 0 n ( − 1 ) j − k ( j k ) 2 j f(k)=\sum_{j=0}^{n}(-1)^{j-k}{j\choose k}2^j f(k)=j=0n(1)jk(kj)2j

感觉这东西可以递推。

然而实际上这东西真的可以递推。

先orz EI 为敬。这道题最早的线性做法就是EI提出来的:EI的blog

我的题解就直接咕咕咕了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}
inline void Mul(int &a,int b){a=mul(a,b);}

int n;

cs int P=2e5+5;

int pw[P];
int pr[P],pcnt;
bool mark[P];
int c[P],inv[P];

inline void linear_sieves(int lim){
	pw[1]=1;
	for(int re i=2;i<=lim;++i){
		if(!mark[i]){
			pw[i]=power(i,n+1);
			pr[++pcnt]=i;
		}
		for(int re j=1;i*pr[j]<=lim;++j){
			mark[i*pr[j]]=true;
			pw[i*pr[j]]=mul(pw[i],pw[pr[j]]);
			if(i%pr[j]==0)break;
		}
	}
	inv[1]=inv[0]=1;c[0]=1,c[1]=n+1;
	for(int re i=2;i<=lim;++i)inv[i]=mul(inv[mod%i],mod-mod/i);
	for(int re i=2;i<=lim;++i)c[i]=mul(c[i-1],mul(n-i+2,inv[i]));
}

int a[P],ans;

signed main(){
	scanf("%d",&n);
	linear_sieves(n+1);
	for(int re i=0;i<=n;++i)a[i]=((n-i)&1)?mod-c[i]:c[i];
	for(int re i=0;i<=n;++i)Mul(a[i],pw[2]);++a[0];
	int p=mul(inv[3],2);
	for(int re i=1;i<=n;++i)Inc(a[i],mul(a[i-1],p));
	ans=add(a[0],mul(a[1],n+1));
	for(int re i=2;i<=n;++i)Inc(ans,mul(mul(pw[i]-1,inv[i-1]),a[i]));
	std::cout<<mul(ans,inv[3])<<"\n";
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值