【题意】 有一个长度为
N
N
N 的基因段,即每一个位置的元素为
A
,
G
,
C
,
T
A,G,C,T
A,G,C,T 中的一个。 首先,我们把每个相邻字母相同的位置进行分割,然后分割的每一段都翻转一下,再拼起来。
A
G
G
A
T
T
T
↓
A
G
∣
G
A
T
∣
T
∣
T
↓
G
A
∣
T
A
G
∣
T
∣
T
↓
G
A
T
A
G
T
T
\begin{matrix} AGGATTT\\ \downarrow\\ AG|GAT|T|T\\ \downarrow\\ GA|TAG|T|T\\ \downarrow\\ GATAGTT \end{matrix}
AGGATTT↓AG∣GAT∣T∣T↓GA∣TAG∣T∣T↓GATAGTT 那么,原串
S
=
A
G
G
A
T
T
T
S=AGGATTT
S=AGGATTT 就变成了果串
T
=
G
A
T
A
G
T
T
T=GATAGTT
T=GATAGTT 给定一个损坏的果串
T
T
T,某些位置为
?
?
? 表示为
A
,
G
,
C
,
T
A,G,C,T
A,G,C,T 中的一个。 问你,该果串合法的原串 的数量为多少?取模
1
e
9
+
7
1e9+7
1e9+7
【范围】
1
≤
N
≤
1
0
5
1\le N\le 10^5
1≤N≤105
思路
考虑一个原串到果串的操作:
A
.
.
.
G
∣
G
.
.
.
C
∣
C
.
.
.
G
∣
G
.
.
.
D
∣
D
↓
G
.
.
.
A
∣
C
.
.
.
G
∣
G
.
.
.
C
∣
D
.
.
.
G
∣
D
\begin{matrix} A...G|G...C|C...G|G...D|D\\ \downarrow\\ G...A|C...G|G...C|D...G|D \end{matrix}
A...G∣G...C∣C...G∣G...D∣D↓G...A∣C...G∣G...C∣D...G∣D 结论一:原串按照分割原则之后形成的小段
(
A
.
.
.
G
)
(
G
.
.
.
C
)
(
C
.
.
.
G
)
(
D
.
.
.
)
(A...G)(G...C)(C...G)(D...)
(A...G)(G...C)(C...G)(D...) 那么,每一个小段的相邻位置一定是不同的。否则,该段还能分成更细的小段。 . 问方案数,大概率就是一个类似计数的
d
p
dp
dp ,考虑怎么去设
d
p
dp
dp 的状态。 考虑到,我们必须进行一段一段地分析。 首先我们假设设
d
p
[
i
]
[
x
]
[
y
]
dp[i][x][y]
dp[i][x][y] 表示目前枚举到第
i
i
i 个位置,最后一个小段的头和尾分别为字母
x
x
x 和字母
y
y
y。 那么新进来一个末尾字母
t
t
t ,该字母应该和最后一段合并,还是新开一个小段? 这个时候貌似状态不够了。我们怎么新加状态呢? . 结论二:对于果串,目前的两个小段的首尾字母为
(
Z
.
.
.
)
(
X
.
.
.
Y
)
(Z...)(X...Y)
(Z...)(X...Y),该两段不一定合法 新加一个字母
t
t
t,变成了
(
Z
.
.
.
)
(
X
.
.
Y
t
)
(Z...)(X..Yt)
(Z...)(X..Yt) 这两个小段能合并的情况就是
Z
=
t
Z=t
Z=t,于是变成了
(
t
.
.
.
)
(
X
.
.
.
t
)
(t...)(X...t)
(t...)(X...t),该两段合法。 . 那么问题来了:为什么我们不记录果串为
(
Z
.
.
.
K
)
(
X
.
.
.
Y
)
(Z...K)(X...Y)
(Z...K)(X...Y) 呢?因为如果前面还存在一些合法的段的话,那么果串的样子就是
(
K
.
.
.
?
)
(
Z
.
.
.
K
)
(
X
.
.
.
Y
)
(K...?)(Z...K)(X...Y)
(K...?)(Z...K)(X...Y),也就是说这个
K
K
K 是不需要考虑的,
K
K
K 要求取遍所有的答案。 . 所以我们记录
d
p
[
i
]
[
x
]
[
y
]
[
z
]
dp[i][x][y][z]
dp[i][x][y][z] 表示目前位置为
i
i
i,最后两段的样子为:
(
Z
.
.
.
)
(
X
.
.
.
Y
)
(Z...)(X...Y)
(Z...)(X...Y),此时的方案数。 【考虑转移】 (合并):如果新进来一个字母
t
t
t ,如果
Z
=
Y
Z=Y
Z=Y 已经成立了,那么
t
t
t 可以自成一段,变成
(
X
.
.
.
)
(
Z
)
(X...)(Z)
(X...)(Z) (不合并):如果
t
≠
Y
t\ne Y
t=Y,那么根据结论一,我们可以把这个字母加到这个段里去,变成
(
Z
.
.
.
)
(
X
.
.
.
t
)
(Z...)(X...t)
(Z...)(X...t) 【考虑答案】 合法答案,就是到末尾位置,最后两段为
(
X
.
.
.
)
(
?
.
.
.
X
)
(X...)(?...X)
(X...)(?...X) . 还有一个问题,我们以上都没有考虑问号字母。问号字母咋处理呢?我们把问号字母当做四种不同的字母,分别去转移即可。
代码
时间复杂度:
O
(
4
4
×
n
)
O(4^4\times n)
O(44×n)
char aa[MAX];int dp[MAX][5][5][5];
map<char,int>Z;intmain(){scanf("%s",aa+1);int n =strlen(aa+1);
Z['A']=0;
Z['G']=1;
Z['C']=2;
Z['T']=3;
Z['?']=4;for(int x =0;x <4;++x)for(int y =0;y <4;++y){/// 第一位稍微搞搞if(Z[aa[1]]==4|| Z[aa[1]]== x)dp[1][x][x][y]=1;}for(int i =2;i <= n;++i)for(int x =0;x <4;++x)for(int y =0;y <4;++y)for(int z =0;z <4;++z){if(Z[aa[i]]==4){for(int t =0;t <4;++t){/// 四种字母分别去跑if(y == z)dp[i][t][t][x]=((ll)dp[i][t][t][x]+ dp[i-1][x][y][z])% MOD;if(t != y)dp[i][x][t][z]=((ll)dp[i][x][t][z]+ dp[i-1][x][y][z])% MOD;}}else{int t = Z[aa[i]];/// 跑一种字母即可if(y == z)dp[i][t][t][x]=((ll)dp[i][t][t][x]+ dp[i-1][x][y][z])% MOD;if(t != y)dp[i][x][t][z]=((ll)dp[i][x][t][z]+ dp[i-1][x][y][z])% MOD;}}
ll res =0;for(int x =0;x <4;++x)for(int y =0;y <4;++y)res =(res +(ll)dp[n][x][y][y])% MOD;printf("%lld",res);return0;}