题目链接
题目大意:给出26个字母距离下一个字母的必须要有的间隙,问最大匹配数。
Input:
2 10
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
AB (范围3e2)
ABBBBABBBB (1e5)
Output:10
样例分析:(1,3), (1, 4), (1, 5), (1, 7), (1, 8), (1, 9), (1, 10), (6, 8), (6, 9), (6, 10)
一开始的时候想过dp,但是看到范围,认为开dp[3e2][1e5]是不可行的。后来学长说是dp,自己认真想了想是这样,没有理数组能不能开这么大去想了,然后就想了一个错误的思路。
错误的思路:dp[i][j] i代表str1到i这个位置与str2到j这个位置的匹配数,错在哪里呢,我的匹配数只是记录了以str1[i]结尾的匹配的数量,当找 i+ 1的时候往回找的时候会找少。
正确的思路:
dp[i][j] 记录到j这个位置,与str1[1~i]匹配的数量。当str1[i] = str2[j]时,dp[i][j] = dp[i][j - 1] + dp[i - 1][j - data[str1[i - 2] - ‘A];不相等就继承上一位的个数dp[i][j - 1]。
代码
#include
using namespace std;
const int maxn = 1e5 + 100;
const int mod = 1e9 + 7;
long long dp[5][maxn];
int data[30];
char str1[maxn], str2[maxn];
int main()
{
int n, k;
scanf("%d %d", &k, &n);
for(int i = 0; i < 26; i++)
{
scanf("%d", &data[i]);
data[i]++;
}
scanf("%s %s", str1, str2);
long long sum = 0;
for(int i = 0; i < n; i++)
{
dp[1][i + 1] = dp[1][i] + (str1[0] == str2[i]);
dp[1][i + 1] %= mod;
}
for(int i = 2; i <= k; i++)
{
for(int j = 1; j <= n; j++)
{
dp[i%2][j] = dp[i%2][j-1];
if(str1[i - 1] == str2[j - 1])
{
if(j - (data[str1[i - 2] - 'A']) >= 0)
{
dp[i%2][j] += dp[(i - 1)%2][j - (data[str1[i - 2] - 'A'])];
dp[i%2][j] %= mod;
}
}
}
}
printf("%lld\n", dp[k % 2][n]);
}
/*
3 29
2 3 5 2 3 3 2 5 2 3 5 3 5 5 5 2 1 4 1 2 3 2 3 1 5 2
PVZ
PPZIWADMJVRVHRTBKJZKUXOZZSAZM
answer :16
*/