1. 程式人生 > 其它 >洛谷P4351 [CERC2015]Frightful Formula【組合計數】

洛谷P4351 [CERC2015]Frightful Formula【組合計數】

經典組合計數問題:棋盤遊走。

[CERC2015]Frightful Formula

Description

定義一個矩陣 \(F\),給定其第一行和第一列,其他位置將通過遞推方式給出,具體的:

\[F_{i,j}=aF_{i,j-1}+bF_{i-1,j}+c \]

\(F(n,n)\)

\(n\le 2\times 10^5\)

Solution

首先考慮 \(c=0\) 的情況,此時原問題可以看作從第二行第二列出發,只能向右或向下走且向右走的權值為 \(a\),向左走的權值為 \(b\) 時所有方案的權值積之和。列舉起點,容易寫出貢獻就是:

\[\sum_{i=2}^{n}l_i\binom{2n-2-i}{n-2}a^{n-1}b^{n-i}+\sum_{i=2}^{n}t_i\binom{2n-2-i}{n-2}a^{n-i}b^{n-1} \]

這一部分可以暴力 \(\mathcal O(n)\)

計算,接下來考慮 \(c\) 對答案的貢獻,列舉 \(c\) 在哪一個位置出現,那麼它的貢獻就是從這個位置到 \((n,n)\) 的所有方案的權值積:

\[c\sum_{i=2}^{n}\sum_{j=2}^{n}\binom{2n-i-j}{n-i}a^{n-j}b^{n-i}\\ =c\sum_{i=2}^{n}\dfrac{b^{n-i}}{(n-i)!}\sum_{j=2}^{n}\dfrac{a^{n-j}(2n-i-j)!}{(n-j)!} \]

這就是一個減法卷積,由於模數為 \(10^6+3\) ,所以需要使用 \(MTT\)

略微有點卡常,考慮優化,回到 \(c\) 的柿子,改為列舉 \(2n-i-j\)

試試?

\[c\sum_{t=0}^{2n-4}\sum_{i=\max(0,t-n+2)}^{n-2}\binom{t}{i}a^{t-i}b^i \]

我們想直接大力二項式定理,但好像上標下標不太對,考慮分 \(t\le n-2\)\(t>n-2\) 分別討論:

\(t\le n-2\):

\[\begin{aligned} &=c\sum_{t=0}^{n-2}\sum_{i=0}^{t}\binom{t}{i}a^{t-i}b^i\\ &=c\sum_{t=0}^{n-2}(a+b)^t \end{aligned} \]

\(t>n-2\):

\[\begin{aligned} &=c\sum_{t=n-1}^{2n-4}\sum_{i=t-n+2}^{n-2}\binom{t}{i}a^{t-i}b^i\\ \end{aligned} \]

\(g_t=\sum_{i=t-n+2}^{n-2}\dbinom{t}{i}a^{t-i}b^i\)

有:

\[\begin{aligned} g_t&=\sum_{i=t-n+2}^{n-2}(\binom{t-1}{i-1}+\binom{t-1}{i})a^{t-i}b^i\\ &=a\sum_{i=t-n+2}^{n-2}\binom{t-1}{i}a^{(t-1)-i}b^i+b\sum_{i=t-n+2}^{n-2}\binom{t-1}{i-1}a^{(t-1)-(i-1)}b^{i-1}\\ \end{aligned} \]

這玩意很像是 \((a+b)g_{t-1}\),但是前者的上下界為 \([t-n+2,n-2]\),後者為 \([t-n+1,n-3]\),距離 \([t-n+1,n-2]\) 都有差距,需要減去多出的部分:

\[g_t=(a+b)g_{t-1}-\binom{t-1}{t-n+1}a^{n-1}b^{t-n+1}-\binom{t-1}{n-2}a^{t-n+1}b^{n-1}\\ \]

於是直接 \(\mathcal O(n)\) 遞推即可。複雜度 \(\mathcal O(n)\)

Code

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10,mod=1e6+3;
int n,a,b,c,l[N],t[N],base[N],jc[N],pwa[N],pwb[N],f[N];
inline int ksm(int x,int y){
	int ret=1;
	for(;y;y>>=1,x=1ll*x*x%mod) if(y&1) ret=1ll*ret*x%mod;
	return ret;
}
inline void init(int n){
	base[0]=1;
	for(int i=1;i<=n;++i) base[i]=1ll*base[i-1]*i%mod;
	jc[n]=ksm(base[n],mod-2);
	for(int i=n-1;i>=0;--i) jc[i]=1ll*jc[i+1]*(i+1)%mod;
	pwa[0]=1;pwb[0]=1;
	for(int i=1;i<=n;++i) pwa[i]=1ll*pwa[i-1]*a%mod,pwb[i]=1ll*pwb[i-1]*b%mod;
}
inline int binom(int x,int y){if(x<y) return 0;return 1ll*base[x]*jc[y]%mod*jc[x-y]%mod;}
inline void inc(int &x,int y){x=(x+y>=mod)?x+y-mod:x+y;}
inline int dec(int x,int y){return (x-y<0)?x-y+mod:x-y;}
int main(){
	scanf("%d%d%d%d",&n,&a,&b,&c);
	init(n<<1);
	int ans=0;
	for(int i=1;i<=n;++i){
		scanf("%d",&l[i]);
		if(i>=2) ans=(ans+1ll*l[i]*binom(n-2+n-i,n-2)%mod*pwa[n-1]%mod*pwb[n-i])%mod;
	}
	for(int i=1;i<=n;++i){
		scanf("%d",&t[i]);
		if(i>=2) ans=(ans+1ll*t[i]*binom(n-2+n-i,n-2)%mod*pwb[n-1]%mod*pwa[n-i])%mod;
	}
	int ret=0;
	for(int t=0,pw=1;t<=n-2;++t,pw=1ll*pw*(a+b)%mod)
		inc(ret,pw);
	for(int t=n-1;t<=2*n-4;++t){
		if(t==n-1){
			f[n-1]=0;
			for(int i=1;i<=n-2;++i) f[n-1]=(f[n-1]+1ll*binom(n-1,i)*pwa[n-1-i]%mod*pwb[i])%mod;
		}
		else{
			f[t]=1ll*f[t-1]*(a+b)%mod;
			f[t]=dec(f[t],1ll*binom(t-1,t-n+1)*pwa[n-1]%mod*pwb[t-n+1]%mod);
			f[t]=dec(f[t],1ll*binom(t-1,n-2)*pwb[n-1]%mod*pwa[t-n+1]%mod);
		}
		inc(ret,f[t]);
	}
	ans=(ans+1ll*ret*c)%mod;
	printf("%d\n",ans);
	return 0;
}