BZOJ3269 序列染色
BZOJ3269 序列染色
做完这题觉得很有意思,结果发现网上都不是我这么做的,那就是我很有意思 😁?
设两个二维 dp \(f[i][j],g[i][j]\) 分别表示目前到了第 i 位,B 匹配到了第 j 个的方案数和 B 已经匹配完成,W 匹配到了第 j 个的方案数。我这里是用所有的方案减去不合法的方案数即 \(2^{cnt}-\sum_{i=0}^{k-1}f_i+g_i\) 注:\(f_k\) 自动挪到 \(g_0\) 上。
考虑如何转移,如果新加入进来一个 B,那么 g 数组归零,f 数组整体右移一位即可,归零指所有的数加到 \(g_0\) 上然后清零即可。新加入 W 同理,加入 X 也是同理。这样我们发现无非是两个操作,把序列的和加到 0 位置上和整体右移,因此我们维护一个指针左移来实现整体右移,同时维护所有的和即可。看起来确实要比网上简洁一些。
/*
/> フ
| _ _|
/`ミ _x 彡
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
*/
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;
template <typename T>
void read(T &x) {
x = 0; bool f = 0;
char c = getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
for (;isdigit(c);c=getchar()) x=x*10+(c^48);
if (f) x=-x;
}
template<typename F>
inline void write(F x, char ed = '\n') {
static short st[30];short tp=0;
if(x<0) putchar('-'),x=-x;
do st[++tp]=x%10,x/=10; while(x);
while(tp) putchar('0'|st[tp--]);
putchar(ed);
}
template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }
template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }
const int P = 1e9 + 7;
ll fpw(ll x, ll mi) {
ll res = 1;
for (; mi; mi >>= 1, x = x * x % P)
if (mi & 1) res = res * x % P;
return res;
}
void add(ll &x, ll y) {
x += y, x >= P && (x -= P);
}
const int N = 4000500;
ll F[N], G[N], *f = F + 2000000, *g = G + 2000000, cnt, n, k;
char s[N];
ll sumf, sumg, clf, clg;
int main() {
// freopen ("color.in","r",stdin);
// freopen ("color.out","w",stdout);
read(n), read(k);
scanf ("%s", s + 1);
clf = clg = k + 1;
sumf = f[0] = 1;
for (int i = 1;i <= n; i++) {
if (s[i] == 'B') {
clg = 1; g[0] = sumg;
if (clf >= k) {
add(g[0], f[k-1]), add(sumg, f[k-1]);
add(sumf, P - f[k-1]);
}
clf++, f--;
}
else if (s[i] == 'W') {
clf = 1, f[0] = sumf;
if (clg >= k) add(sumg, P - g[k-1]);
g--, clg++;
}
else if (s[i] == 'X') {
cnt++;
ll s1 = sumf, s2 = sumg;
ll t = clf >= k ? f[k-1] : 0, tg = clg >= k ? g[k-1] : 0;
f--, g--, clf++, clg++;
add(sumf, sumf), add(sumg, sumg), add(sumf, P - t), add(sumg, P - tg);
f[0] = s1, g[0] = s2, add(g[0], t), add(sumg, t);
}
}
ll ans = fpw(2, cnt);
for (int i = 0;i < k; i++) {
if (clf > i) add(ans, P - f[i]);
if (clg > i) add(ans, P - g[i]);
}
write(ans);
return 0;
}