卡特蘭數 相關問題 hdu 5184 Brackets
阿新 • • 發佈:2019-02-11
題解:
qp+q−Cq−1p+q=p−q+1p+1Cqp+q然後對100W以內的數字進行一個階乘處理,就可以O(1)得出答案了。
當n為奇數的時候答案是0。 先判斷字串的前面是否符合括號匹配,即對於任何字首左括號個數>=右括號個數。 設左括號個數為a右括號個數為b, m=n/2,問題可以轉化為在平面中從座標(a,b)沿網格走到(m,m) 且不跨過x=y這一條直線的方法數。資料太大,普通DP和搜尋都不行的。 問題可以進一步轉化為從(a-n,b-n)到(0,0)且不跨過x=y的方法數。再對稱一下,轉化到(0,0)到(n-b,n-a)不跨過x=y的方法數。 對於從(0,0)點走到(p,q)點不跨過x=y的方法數是p−q+1p+1Cqp+q證明如下: 我們可以通過總的數目來減掉非法的數目即可。 把(0,0)和(p,q)都往下移一格,非法數目即為(0,-1)到(p,q-1)且路徑中至少有一點和x=y相交的方法數。記(d,d)為從(0,-1)到(p,q-1)路徑中最先和x=y相交的點。則由於對稱性(-1,0)到(d,d)的方法數和(0,-1)到(d,d)的方法數是相同的。所以(0,-1)到(p,q-1)且與x=y相交的方法數和(-1,0)到(p,q-1)的方法數是相同的。 所以答案是C
相關問題:
經典的買票問題,:本次足球比賽的門票為50元,而站排買票的球迷有m個人手裡拿著一張面值50元的鈔票,有n個人手裡拿著一張面值100元的鈔票。工作人員事先忘了為售票處準備任何零錢,請問您是否能算出這(m+n)個人共有多少種排隊方式買票,使售票處不至於出現找不開錢的尷尬局面?
問題即p個‘(’,q個‘)’,p>=q,滿足條件的排列數,答案即為Cqp+q−Cq−1p+q=p−q+1p+1Cqp+q
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<iostream> #include<algorithm> #include<vector> #include<utility> #include<queue> #include<set> #include<map> #include<math.h> #include<string> using namespace std; #define inf 0x3f3f3f3f #pragma warning(disable:4996) #pragma comment(linker, "/STACK:102400000,102400000") #define ll long long #define mp make_pair #define pb push_back #define pii pair<int,int> #define mem(a,b) memset(a,b,sizeof(a)) const double eps = 1e-9; const ll mod = 1e9 + 7; #define N 1000000 char p[1000010]; ll h[N+10]; //階乘表 ll g[N+10]; //階乘逆元表 ll inv(ll a, ll mod) { return a == 1 ? 1 : (mod - mod / a) * inv(mod % a, mod) % mod; } ll C(int a, int b) { if (a < b) return 0; return h[a] * g[b] % mod*g[a - b] % mod; } void init() { int i; h[0] = 1; for (i = 1; i <= N; i++) h[i] = h[i - 1] * i%mod; g[N] = inv(h[N], mod); for (i = N; i >= 1; i--) g[i - 1] = g[i] * i%mod; } int main() { int i, j, k; int n; init(); while (scanf("%d", &n) != EOF) { scanf("%s", p); if (n & 1) { printf("0\n"); continue; } int sum = 0; int len = strlen(p); int flag = 0; for (i = 0; i < len; i++) { if (p[i] == '(') sum++; else sum--; if (sum < 0) { flag = 1; break; } } if (flag == 1) { printf("0\n"); continue; } n -= len; if (n == 0) { if (sum == 0) printf("1\n"); else printf("0\n"); continue; } if (n < sum) { printf("0\n"); continue; } if (n == sum) { printf("1\n"); continue; } if ((n - sum) % 2 == 1) { printf("0\n"); continue; } int th = (n - sum) / 2; int q = th, p = th + sum; ll ans = C(p + q, q)*(p - q + 1) % mod*inv(p + 1, mod) % mod; printf("%I64d\n", ans); } }