CodeForces 204D Little Elephant and Retro Strings
题目描述:
输入一个由 W 、 B 和 X 组成的字符串,你可以把 X 字符替换成 W 或者 B ,问有多少种方案使得,可以找到两个不相交的长度问 K 的区间,左边的全都由 B 组成,右边的全部由 W 组成。
题解:
为了避免重复,仅考虑最左边的长度为 K 的全 B 区间和最右边的长度为 K 的全 W 区间。
这个方案数很好求,以左边的为例,假设在前缀 i 的位置刚好出现了一个满足条件的区间 [i−K,i] ,那么前缀 i 仅出现一次满足要求的区间的方案数就是前缀 i−1 的方案数,加上前缀 i−K−1 中没有满足要求的区间(这保证了区间 [i−K,i] 首次出现)的方案数。
右边的用同样的方式求,最后把两个合并起来就行了。
代码:
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define MAXN 1000007
const long long MOD = 1000000007LL;
static int N, K;
static long long sum, not_b[MAXN], not_w[MAXN], dp[MAXN], num[MAXN];
static char S[MAXN];
inline long long pow(long long x, long long y)
{
long long ans = 1;
for (; y; y >>= 1, (x *= x) %= MOD)
if (y & 1) (ans *= x) %= MOD;
return ans;
}
int main()
{
scanf("%d%d%s", &N, &K, S + 1);
num[N + 1] = 1;
for (int i = N; i; i--)
num[i] = S[i] == 'X' ? 2LL * num[i+1] % MOD : num[i+1];
not_b[0] = 1;
for (int i = 1, last = 0; i <= N; i++)
{
last = S[i] == 'W' ? 0 : last + 1;
not_b[i] = S[i] == 'X' ? 2LL * not_b[i-1] % MOD : not_b[i-1];
dp[i] = dp[i-1];
if (K <= last && S[i-K] != 'B')
{
long long sub = i == K ? 1 : not_b[i-K-1];
(not_b[i] += MOD - sub) %= MOD;
(dp[i] += sub * num[i+1]) %= MOD;
}
}
not_w[N + 1] = not_w[N + 2] = 1;
for (int i = N, last = 0; i; i--)
{
last = S[i] == 'B' ? 0 : last + 1;
not_w[i] = S[i] == 'X' ? 2LL * not_w[i+1] % MOD : not_w[i+1];
if (K <= last && S[i+K] != 'W')
{
long long sub = not_w[i+K+1];
(not_w[i] += MOD - sub) %= MOD;
(sum += sub * dp[i-1] % MOD * pow(num[i], MOD - 2) % MOD) %= MOD;
}
}
printf("%lld\n", sum);
return 0;
}
提交记录(AC / Total = 1 / 1):
Run ID | Remote Run ID | Time(ms) | Memory(kb) | Result | Submit Time |
---|---|---|---|---|---|
8772863 | 26349680 | 1060 | 34140 | AC | 2017-04-14 11:05:14 |