Bovine Genetics G
题目链接:luogu P7152
题目大意
定义把一个字符串操作时在所有连续相同位置切开字符串,把每一段反转再接上。
然后给你一个操作后的序列,有一些位置不知道,问你原来的字符串有多少可能。
思路
首先不难发现,对于一个字符串,你用不同的方式把它分段,得出来的原始串也会不一样。
那这让我们考虑用 DP 来做。
但是我们要想怎么分段才是合法的。
首先,一段内肯定不能有连续相同的。
接着,它翻转之后要两个旁边是相同的,那就是说,一个串的最后一个字符要等于上一个串的第一个字符。
不难想到有关的就只有上一个串的第一个字符,最后一个字符,你现在的字符。
(然后为了能够转移第一个字符,你还需要这个字符串的第一个字符)
那现在的字符不用枚举(如果是问号就都枚举一下),剩下的你就都枚举一下,反正
4
3
4^3
43 (有问号就是
4
4
4^4
44)无伤大雅。
然后就是设
f
i
,
j
,
k
,
l
f_{i,j,k,l}
fi,j,k,l 为前
i
i
i 个搞好,上一段第一个是
l
l
l,这一段第一个是
j
j
j,最后一个是
k
k
k 的方案数。
然后你考虑现在一个字符
n
o
w
now
now,怎么可以开新段,怎么可以加进这一段。
那如果两个不相同,就可以加进这一段,就是
n
o
w
≠
k
now\neq k
now=k,那就可以
f
i
,
j
,
n
o
w
,
l
+
=
f
i
−
1
,
j
,
k
,
l
f_{i,j,now,l}+=f_{i-1,j,k,l}
fi,j,now,l+=fi−1,j,k,l。
那如果之前的最后一个等于上一段第一个(
k
=
l
k=l
k=l),就可以开新段,就是
f
i
,
n
o
w
,
n
o
w
,
j
+
=
f
i
−
1
,
j
,
k
,
l
f_{i,now,now,j}+=f_{i-1,j,k,l}
fi,now,now,j+=fi−1,j,k,l。
然后初始状态就拿第一个字符去搞,然后从第二个字符开始 DP。
最后记得也要
k
=
l
k=l
k=l 才可以统计入答案。
记得取模。
代码
#include<cstdio>
#include<cstring>
#define ll long long
#define mo 1000000007
using namespace std;
char c[100001];
ll f[100001][4][4][4], ans;
int n;
int get_bh(char x) {
if (x == 'A') return 0;
if (x == 'C') return 1;
if (x == 'G') return 2;
return 3;
}
int main() {
scanf("%s", c + 1);
n = strlen(c + 1);
if (c[1] == '?') {//先根据第一个搞预先状态
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
f[1][i][i][j] = 1;
}
else {
for (int j = 0; j < 4; j++)
f[1][get_bh(c[1])][get_bh(c[1])][j] = 1;
}
for (int i = 2; i <= n; i++)//转移
for (int j = 0; j < 4; j++)
for (int k = 0; k < 4; k++)
for (int l = 0; l < 4; l++) {
int now = get_bh(c[i]);
if (c[i] == '?') {
for (now = 0; now < 4; now++) {
if (now != k) {
f[i][j][now][l] = (f[i][j][now][l] + f[i - 1][j][k][l]) % mo;
}
if (k == l) {
f[i][now][now][j] = (f[i][now][now][j] + f[i - 1][j][k][l]) % mo;
}
}
}
else {
if (now != k) {
f[i][j][now][l] = (f[i][j][now][l] + f[i - 1][j][k][l]) % mo;
}
if (k == l) {
f[i][now][now][j] = (f[i][now][now][j] + f[i - 1][j][k][l]) % mo;
}
}
}
for (int j = 0; j < 4; j++)//统计答案
for (int k = 0; k < 4; k++)
ans = (ans + f[n][j][k][k]) % mo;//记得也要遵守规则
printf("%lld", ans);
return 0;
}