1. 程式人生 > >Luogu 1641[SCOI2010]生成字符串 - 卡特蘭數

Luogu 1641[SCOI2010]生成字符串 - 卡特蘭數

div pri pen span cstring cst clas hid using

Description

有$N$ 個 $1$ 和 $M$ 個 $0$ 組成的字符串, 滿足前 $k$ 個字符中 $1$ 的個數不少於 $0$ 的個數。

求這樣字符串的個數。

$1<=M <=N<=1e6$

Solution

正難則反, 很難直接求出滿足條件的字符串的個數, 就從反面考慮。

$N$個$1$ 和 $M$ 個 $0$ 組成的字符串總共有 $C(N + M, N)$ 個, 再減去不滿足條件的 字符串的個數就能夠得到答案了。

不滿足條件的字符串個數為$C(N+M,N+1)$

證明與 卡特蘭數的證明類似:

設一個 不滿足條件的字符串 $0$ 的個數 比 $1$ 多 的 位置為 $k$。

並且 對於任意 $j <k$, 前$j$個字符中$num_1>=num_0$, 而前$k$個字符$num_1<num_0$。

很顯然 $num_0=num_1+1$, 我們將這個 $k$ 個字符都取反, $0$ 變成 $1$, $1$ 變成 $0$。

$0$ 的個數減少 $1$ 個, $1$ 的個數 增加 $1$個,

那麽取反後的字符串 中 $1$ 的個數為 $N+1$, $0$ 的個數為 $M-1$。

由於 $N+1$個$1$ ,$M-1$個$0$ 組成的字符串恰好有$C(N+M,N+1)$個。

所以我們接下來要證明 它們是 一 一對應的,(即$(N,M)$中不滿足條件的字符串通過轉換能 對應上 $(N+1, M-1)$ 每種

字符串)

  現在已知 $(N,M)$ 能通過轉換變成 $(N+1,M-1)$ 且沒有重復。

  只需證明$(N+1,M-1)$ 通過轉換 變成 $(N,M)$ : 找到第一個 $1$ 比 $0$ 多的位置 $k$ 並把前 $k$ 個字符取反 即可。

證畢

最後答案就是 $C(N+M,N)-C(N+M,N+1)$。

Code

技術分享圖片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace
std; 6 7 const int mod = 20100403; 8 const int N = 2e6 + 5; 9 10 ll fpow(ll a, ll b) { 11 ll re = 1; 12 for (; b; b >>= 1, a = a * a % mod) 13 if (b & 1) re = re * a % mod; 14 return re; 15 } 16 17 ll fac[N], ans; 18 19 int main() 20 { 21 int n, m, M; 22 scanf("%d%d", &n, &m); 23 M = n + m; 24 fac[0] = fac[1] = 1; 25 for (int i = 1; i <= M; ++i) 26 fac[i] = fac[i - 1] * i % mod; 27 ans = fac[M] * fpow(fac[n], mod - 2) % mod; 28 ans = ans * fpow(fac[m], mod - 2) % mod; 29 ll tmp = fac[M] * fpow(fac[n + 1], mod - 2) % mod; 30 tmp = tmp * fpow(fac[m - 1], mod - 2) % mod; 31 ans = ans - tmp; 32 ans = (ans % mod + mod) % mod; 33 printf("%lld\n", ans); 34 }
View Code

  

Luogu 1641[SCOI2010]生成字符串 - 卡特蘭數