CodeForces 204D Little Elephant and Retro Strings

CodeForces 204D Little Elephant and Retro Strings

题目描述:

输入一个由 W 、 B 和 X 组成的字符串,你可以把 X 字符替换成 W 或者 B ,问有多少种方案使得,可以找到两个不相交的长度问 K 的区间,左边的全都由 B 组成,右边的全部由 W 组成。

题解:

为了避免重复,仅考虑最左边的长度为 K 的全 B 区间和最右边的长度为 K 的全 W 区间。

这个方案数很好求,以左边的为例,假设在前缀 i 的位置刚好出现了一个满足条件的区间 [iK,i] ,那么前缀 i 仅出现一次满足要求的区间的方案数就是前缀 i1 的方案数,加上前缀 iK1 中没有满足要求的区间(这保证了区间 [iK,i] 首次出现)的方案数。

右边的用同样的方式求,最后把两个合并起来就行了。

题目链接: vjudge 原网站

代码:

#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 IDRemote Run IDTime(ms)Memory(kb)ResultSubmit Time
877286326349680106034140AC2017-04-14 11:05:14
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值