BZOJ2958 序列染色

果然清华集训的题目。。。显然的DP题但是不会做。。。

我们令f[i][j][w]表示状态方程

w表示到了字符串的第w个

i = 0, 1, 2分别表示k个B和k个W都没填上、k个B填上了k个W没填上、k个B和k个W都填上了三种状态

j = 0, 1分别表示第w位上填B/W

于是方程就比较容易列出来了,注意要用到容斥原理

 1 /**************************************************************
 2     Problem: 2958
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:652 ms
 7     Memory:33032 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11  
12 using namespace std;
13 const int N = 1000005;
14 const int mod = 1e9 + 7;
15  
16 int n, k;
17 char st[N];
18 int s0[N], s1[N], f[3][2][N];
19  
20 void read_in() {
21   int i;
22   char ch = getchar();
23   while (ch != 'W' && ch != 'B' && ch != 'X')
24     ch = getchar();
25   for (i = 1; i <= n; ++i)
26     st[i] = ch, ch = getchar();
27 }
28  
29 inline int calc(char c, int *s, int i, int t) {
30   if (i < k || st[i - k] == c || s[i] - s[i - k]) return 0;
31   return f[t - 1][i == k ? 0 : 2 - t][i - k];
32 }
33  
34 int main() {
35   int i;
36   scanf("%d%d", &n, &k);
37   read_in();
38   f[0][0][0] = 1;
39   for (i = 1; i <= n; ++i) {
40     s0[i] = s0[i - 1] + (st[i] == 'W');
41     s1[i] = s1[i - 1] + (st[i] == 'B');
42     if (st[i] != 'W') {
43       f[0][0][i] = (0ll + f[0][1][i - 1] + f[0][0][i - 1] - calc('B', s0, i, 1) + mod) % mod;
44       f[1][0][i] = (0ll + f[1][0][i - 1] + f[1][1][i - 1] + calc('B', s0, i, 1)) % mod;
45       f[2][0][i] = (0ll + f[2][0][i - 1] + f[2][1][i - 1]) % mod;
46     }
47     if (st[i] != 'B') {
48       f[0][1][i] = (0ll + f[0][1][i - 1] + f[0][0][i - 1]) % mod;
49       f[1][1][i] = (0ll + f[1][0][i - 1] + f[1][1][i - 1] - calc('W', s1, i, 2) + mod) % mod;
50       f[2][1][i] = (0ll + f[2][0][i - 1] + f[2][1][i - 1] + calc('W', s1, i, 2)) % mod;
51     }
52   }
53   printf("%d
", (f[2][0][n] + f[2][1][n]) % mod);
54   return 0;
55 }
View Code

(p.s. Orz 江哥...)

By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
原文地址:https://www.cnblogs.com/rausen/p/4264103.html