codeforces#343 C. Famil Door and Brackets dp
As Famil Door’s birthday is coming, some of his friends (like Gabi) decided to buy a present for him. His friends are going to buy a string consisted of round brackets since Famil Door loves string of brackets of length n more than any other strings!
The sequence of round brackets is called valid if and only if:
- the total number of opening brackets is equal to the total number of closing brackets;
- for any prefix of the sequence, the number of opening brackets is greater or equal than the number of closing brackets.
Gabi bought a string s of length m (m ≤ n) and want to complete it to obtain a valid sequence of brackets of length n. He is going to pick some strings p and q consisting of round brackets and merge them in a string p + s + q, that is add the string p at the beginning of the string s and string q at the end of the string s.
Now he wonders, how many pairs of strings p and q exists, such that the string p + s + q is a valid sequence of round brackets. As this number may be pretty large, he wants to calculate it modulo 109 + 7.
First line contains n and m (1 ≤ m ≤ n ≤ 100 000, n - m ≤ 2000) — the desired length of the string and the length of the string bought by Gabi, respectively.
The second line contains string s of length m consisting of characters '(' and ')' only.
Print the number of pairs of string p and q such that p + s + q is a valid sequence of round brackets modulo 109 + 7.
4 1
(
4
4 4
(())
1
4 3
(((
0
In the first sample there are four different valid pairs:
- p = "(", q = "))"
- p = "()", q = ")"
- p = "", q = "())"
- p = "", q = ")()"
In the second sample the only way to obtain a desired string is choose empty p and q.
In the third sample there is no way to get a valid sequence of brackets.
这题想了几天才理清思路,太弱了。。。
求将长度为m的括号序列s补成长度为n的合法括号序列的方案数,可以补前缀和后缀。
首先算出s左边需要的左括号数x和右边需要的右括号数y,这样可以知道,添加的前缀消掉匹配的括号后必然剩下至少x个左括号,最多当然是前缀的长度个了。
这样我们可以枚举前缀的长度和前缀消掉匹配的括号数后剩下的左括号数,显然后缀的长度和后缀消掉匹配后剩下的右括号数也是已知的,两个方案数相乘就可以了。
现在问题在于如何求长度为i,消掉匹配后剩下的左括号数为j的方案数(由于后缀是对称的,所以按前缀算了)。
设长度为i,消掉匹配后剩下j个左括号的方案数为dp[i][j],那么
如果第i个为左括号,前i-1个的左括号数显然是j-1;如果第i个为右括号,前i-1个的消掉匹配后的左括号数为j+1,因为一个右括号被去掉了,必然前面有一个左括号多了出来。
因此,dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1],问题就解决了。
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; const ll MOD=1e9+7; int n,m; char s[maxn]; ll dp[2010][2010]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE while(cin>>n>>m>>s){ int len=strlen(s); int x=0,y=0; REP(i,0,len-1){ if(s[i]=='(') y++; else if(y) y--; else x++; } MS0(dp); dp[0][0]=1; REP(i,1,2002){ REP(j,0,i){ if(j>=1) dp[i][j]=(dp[i-1][j-1]+dp[i-1][j+1])%MOD; else dp[i][j]=dp[i-1][j+1]%MOD; } } ll ans=0; REP(i,x,n-m){ REP(j,x,i){ int k=n-m-i,l=j-x+y; if(l>k) continue; ans=(ans+(dp[i][j]*dp[k][l])%MOD)%MOD; } } cout<<ans<<endl; } return 0; }