E. Sereja and Squares
http://codeforces.com/contest/314/problem/E
题意:
给你一个擦去了部分左括号和全部右括号的括号序列,括号有25种,用除x之外的小写字母a~z表示。在擦去的地方填入一括号,求有多少种合法的括号序列。答案对4294967296取模。
分析:
首先dp的时候如果前面的一个左括号确定了,右边也就确定了(和它一样就行了)。左边不确定的时候'?',假设随便填入一个,最后乘以25就行了。所以状态只与左括号的个数有关。所以可以dp[i][j]表示到第i个位置,有j个左括号。考虑新加入的一个会消去左括号还是加入左括号就行了。复杂度n^2。
优化:因为状态与左括号的个数有关,那么同样可以记录右括号的个数。考虑新加入一个消去了还是增加了。因为前i个中最多i/2个(如果记录左括号的话, 前i个便不满足这个性质,它可以有很多个,后面再很多右括号)。所以转移到i/2。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 using namespace std; 8 typedef unsigned int ui; 9 10 inline int read() { 11 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 12 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 13 } 14 15 char s[100005]; 16 ui f[100005]; 17 18 int main() { 19 int n = read(); 20 if (n & 1) { 21 cout << 0; return 0; 22 } 23 scanf("%s", s + 1); 24 int cnt = 0; 25 f[0] = 1; 26 for (int i=1; i<=n; ++i) { 27 if (s[i] == '?') 28 for (int j=(i>>1); j&&j>=(i-n/2); --j) f[j] += f[j - 1]; 29 else cnt ++; 30 } 31 ui ans = f[n / 2]; 32 for (int i=1; i<=(n/2-cnt); ++i) ans = ans * 25; 33 cout << ans; 34 return 0; 35 }