题解:P7152 [USACO20DEC] Bovine Genetics G
洛谷P7152 [USACO20DEC] Bovine Genetics G
首先可以转换一下题意。
我们对于一个串,需要将这个串反向划分成几段,这样比较直观的求出原来的串。
就像样例 GATAGTT -> GA|TAG|T|T 就是一种反向划分的例子。
我们看得出来划分受到几个约束的限制:
-
块内不能出现连续的字符,否则原串一定会从这个地方断开。
-
相邻块间,左块的左端点与右块相等。
我们由上面两种限制设计连续段 DP 状态。
考虑
转移有两种,一种是新开一段,一种是在后面加。
后面括号里的是限制条件,分别对应以上提到的两条。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100, MOD = 1e9 + 7;
int n, m, dp[N][4][4][4], ans;
string s, ori = "AGCT";
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> s;
int now = 1;
for (int j = 0; j < 4; j++) {
if (s[0] != '?' && s[0] != ori[j]) continue;
for (int i = 0; i < 4; i++) {
dp[0][j][j][i] = 1;
}
}
for (int i = 1; i < s.size(); i++) {
for (int j = 0; j < 4; j++) {
if (s[i] != '?' && s[i] != ori[j]) continue; // 如果有 '?' 的话直接看成四个都转移
for (int b = 0; b < 4; b++) {
for (int c = 0; c < 4; c++) {
for (int k = 0; k < 4; k++) {
if (k != j) dp[i][j][b][c] = (dp[i][j][b][c] + dp[i - 1][k][b][c]) % MOD;
if (k == c) dp[i][j][j][b] = (dp[i][j][j][b] + dp[i - 1][k][b][c]) % MOD;
}
}
}
}
}
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
ans = (ans + dp[s.size() - 1][j][i][j]) % MOD;
}
}
cout << ans;
return 0;
}