CF 314 E. Sereja and Squares

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 }
原文地址:https://www.cnblogs.com/mjtcn/p/9716794.html