洛谷P1641 [SCOI2010]生成字符串(排列組合+逆元)

原文鏈接:https://www.luogu.org/blog/user29936/solution-p1641

原文鏈接

https://www.luogu.org/blog/user29936/solution-p1641

題目鏈接

https://www.luogu.org/problem/P1641

題目描述

lxhgww最近接到了一個生成字符串的任務,任務需要他把n個1和m個0組成字符串,但是任務還要求在組成的字符串中,在任意的前k個字符中,1的個數不能少於0的個數。現在lxhgww想要知道滿足要求的字符串共有多少個,聰明的程序員們,你們能幫助他嗎?

輸入格式

輸入數據是一行,包括2個數字n和m

輸出格式

輸出數據是一行,包括1個數字,表示滿足要求的字符串數目,這個數可能會很大,只需輸出這個數除以20100403的餘數

輸入輸出樣例

輸入 #1

2 2

輸出 #1

2

說明/提示

limitation

每點2秒

對於30%的數據,保證1<=m<=n<=1000

對於100%的數據,保證1<=m<=n<=1000000

來源:SCOI 2010

題解

可以考慮把11的個數與00的個數的看成xx座標,11的個數與00的個數的看成yy座標,那麼如下圖:

這裏寫圖片描述

向右上走(xx座標加11,yy座標加11)就表示這個字符選擇11。

向右下走(xx座標加11,yy座標減11)就表示這個字符選擇00。

這樣子,如果不考慮限制條件,就表示從(0,0)(0,0)走n+mn+m步到達(n+m,n-m)(n+m,n−m),這相當於從n+mn+m步中選出mm步向右下走,也就是C(n+m,m)C(n+m,m)。

考慮限制條件,任意前綴中11的個數不少於00的個數,也就是這條路徑不能經過直線y=-1y=−1。可以通過對稱性發現,從(0,0)(0,0)走到直線y=-1y=−1上的一點,相當於從(0,-2)(0,−2)走到該點。也就是說,路徑經過直線y=-1y=−1的方案數就是從(0,-2)(0,−2)走n+mn+m步到達(n+m,n-m)(n+m,n−m),這個方案數可以用組合數表示爲C(n+m,m-1)C(n+m,m−1)。

所以最後結果爲C(n+m,m)-C(n+m,m-1)C(n+m,m)−C(n+m,m−1)。對於組合數,可以預處理階乘後用乘法逆元計算。

代碼

#include <bits/stdc++.h>
#define maxn 1000010
#define ll long long
using namespace std;
const ll mod=20100403;

ll ni[maxn*2],n,m;
void init(){
	ll i;
	memset(ni,0,sizeof(ni));
	ni[1]=1;
	for(i=2;i<n+m+1;i++)ni[i]=-ni[mod%i]*(mod/i)%mod+mod;
}
 
int main(){
	ll i,a1,a2;
	cin>>n>>m;
	init();
	a1=1;
	for(i=1;i<=n+m;i++){
		a1*=i;
		a1%=mod;
	}
	
	for(i=1;i<=n;i++){
		a1*=ni[i];
		a1%=mod;
	}
	
	for(i=1;i<=m;i++){
		a1*=ni[i];
		a1%=mod;
	}
	
	a2=a1;
	a2=((a2*ni[n+1])%mod*m)%mod;
	cout<<(a1-a2+mod)%mod;
	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章