题目

题目传送门

题目大意:给你一个由’0’,’1’,’?’组成的串,’?’可以为’0’or’1’,每次操作你可以在原串中选连续的三个数使他们合并为他们的中位数
如’010’可以变成’0’,求有多少种方案(关于’?’的取值)使得原串是能在若干次操作后变为’1’(即beautiful的)

题解

我们可以发现如果对所有可能的01串构建自动机,那么这个自动机的状态是有限的,然后我们就可以在自动机上DP求方案数啦
具体构建方法可以看下图和代码(不要嫌弃我画的图丑QAQ……
蓝色是0边,红色是1边,红色节点是beautiful的节点

自动机
自动机

刚开始看错题了,把中位数看成了中间的数卡了好久……英语差……

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int P=1e9+7;
char st[300005];
int f[300005][8],ch[8][2]; //f[i][j]表示匹配到字符串中第i个字符自动机上第j个节点的方案数,ch[i][j]表示自动机上第i个节点接受j后到达的节点
void build()
{
ch[0][0]=2; ch[0][1]=1; //0节点为空串
ch[1][0]=3; ch[1][1]=5; //1节点为1
ch[2][0]=4; ch[2][1]=7; //2节点为0
ch[3][0]=6; ch[3][1]=1; //3节点为10
ch[4][0]=2; ch[4][1]=2; //4节点为00
ch[5][0]=5; ch[5][1]=5; //5节点为11
ch[6][0]=3; ch[6][1]=3; //6节点为100
ch[7][0]=2; ch[7][1]=1; //7节点为01
}
int main()
{
build();
scanf("%s",st+1);
int n=strlen(st+1);
f[n][1]=f[n][5]=1; //节点1和5是一定beautiful的
for (int i=n-1; i>=0; i--)
for (int j=0; j<=7; j++)
{
if (st[i+1]!='1') f[i][j]+=f[i+1][ch[j][0]];
if (st[i+1]!='0') f[i][j]+=f[i+1][ch[j][1]];
if (f[i][j]>=P) f[i][j]-=P;
}
printf("%d\n",f[0][0]);
return 0;
}