[題解]P1641 生成字串

Sinktank發表於2024-11-22

P1641 [SCOI2010] 生成字串

由題意可設\(f[i][j]\)表示用了\(i\)\(0\)\(j\)\(1\)的答案,那麼有轉移:

\[f[i][j]=\begin{cases} 0&i>j\\ f[i][j-1]&i=j\\ f[i-1][j]+f[i][j-1]&i<j\\ \end{cases}\]

狀態數是\(O(n^2)\),轉移是\(O(1)\),總時間複雜度\(O(n^2)\),期望得分\(30\text{ pts}\)


我們用數形結合的方式思考:

如圖,我們將填\(1\)視為向右走\(1\)個單位長度,填\(0\)視為向上走\(1\)個單位長度,最終到達\((n,m)\)視為完成,此時點的軌跡形成了一條折線。每條折線對應一種方案,總方案數是\(C_{n+m}^n\)

顯然,當前方案是合法的\(\iff\)折線的每個頂點都不在直線\(y=x\)上方。

換句話說,當前方案不合法\(\iff\)折線與\(y=x+1\)有交點。

對於每個不合法的方案,我們選定其中一個交點,將它之前的折線沿著\(y=x+1\)翻折,得到圖中橙色的虛線。我們將橙色折線與剩餘的紅色折線形成的部分記作折線\(b\)

可以發現,\(b\)可以取到的形態,與不合法的方案是一一對應的。

所以不合法的方案數就是從\((-1,-1)\)走到\((n,m)\)的方案數,即\(C_{n+m}^{n+1}\)

因此合法方案數就是\(C_{n+m}^n-C_{n+m}^{n+1}\),可以化簡得到\(\frac{(n+m)!\times (n-m+1)}{(n+1)!\times m!}\)

Catalan數\(H_n=C_{2n}^n-C_{2n}^{n-1}\)可以由此題的結論推得,相當於此題\(n=m\)的情況。

計算它需要使用逆元,此處使用費馬小定理。

點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define N 1000010
#define mod 20100403
using namespace std;
int n,m,inv[N],inv_fact[N];
int fac(int r){
	int ans=1;
	for(int i=1;i<=r;i++) ans=ans*i%mod;
	return ans;
}
signed main(){
	cin>>n>>m;
	inv_fact[1]=inv[1]=1;
	for(int i=2;i<=n+1;i++) inv[i]=(-mod/i*inv[mod%i]%mod+mod)%mod;
	for(int i=2;i<=n+1;i++) inv_fact[i]=inv_fact[i-1]*inv[i]%mod;
	cout<<fac(n+m)*(n-m+1)%mod*inv_fact[n+1]%mod*inv_fact[m]%mod<<"\n"; 
	return 0;
}

相關文章