[Atcoder AGC 022 -E] Median Replace

36 篇文章 1 订阅
19 篇文章 0 订阅
Atcoder传送门

题目大意

给你一个长度为 N N 的字符串S,只包含 0,1 0 , 1 x x x可以视为 0 0 1

现在你要执行 N12 N − 1 2 次操作,每次选取连续的一段长度为 3 3 的字符串, 将其替换为其中数量较多的一个字符。例如, 001换为 0 0 111换为 1 1 , 而1x0可换为 1 1 0

现在请你输出经过 N12 N − 1 2 次操作后,剩下的一个字符恰好为 1 1 的方案数(对1000000007取模)。

输入输出格式

输入格式

一行一个字符串 S S

输出格式

一个整数x, 表示方案数(对 1000000007 1000000007 取模)。

数据范围

N300000 N ≤ 300000 , 保证 N N 为奇数。

输入输出样例

输入样例#1

1??00

输出样例#1

2

#### 输入样例#2

?0101???10???00?1???????????????0????????????1????0

输出样例#2

402589311

解题分析

毕克Dark♂佬讲的一道妙妙的题。考虑对01串建立自动机:

图中红边为接收到1的转移, 绿边为接受到 0 0 的转移。

可以发现如果有11出现, 我们总是可以先转移后面的字符串使最后前3个字符为 111 111 110 110 ,所以有一个自环。

注意到 100 100 是一种特殊情况, 因为 1000 1000 的时候我们并不是将前面三个字符 100 100 合并成 0 0 ,而是将000合并为 0 0 , 所以这里要多加一个状态。

然后我们就可以在自动机上DP啦… 如果是x就向两种字符都转移一下, 最后求一下 1 1 11状态的方案和就可以了。

复杂度 O(8×N) O ( 8 × N )

代码如下:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define ll long long
#define MX 300050
#define mod 1000000007
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    W (!isdigit(c)) c = gc;
    W (isdigit(c))
    x = (x << 1) + (x << 3) + c - 48, c = gc;
}
short go[8][2] = {{2, 1}, {4, 3}, {6, 5}, {3, 3}, {7, 1}, {2, 1}, {2, 2}, {4, 4}};//打表转移
ll dp[MX][8];
char buf[MX];
int len;
int main(void)
{
    scanf("%s", buf + 1);
    len = std::strlen(buf + 1);
    dp[0][0] = 1; 
    R int j;
    for (R int i = 0; i < len; ++i)
    {
        for (j = 0; j <= 7; ++j)
        {
            if(buf[i + 1] != '0') dp[i + 1][go[j][1]] += dp[i][j], dp[i + 1][go[j][1]] %= mod;
            if(buf[i + 1] != '1') dp[i + 1][go[j][0]] += dp[i][j], dp[i + 1][go[j][0]] %= mod;
        }
    }
    printf("%d\n", (dp[len][1] + dp[len][3]) % mod);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值