题目大意
给你一个长度为n的字符串S, 只包含小写字母, q个请求, 每个请求由m c构成, 问改变字符串中的m个字母, 求只包含字母c的最长连续子串长度是多少
解题思路
设sum[ch][i] := S前i个字母包含字符ch的个数, 预处理出这个, 可以快速求出任意区间内某字母的个数
dp[ch][i] := 改变i个字符, 最长的只包含ch的子串的长度
对于区间[i, j], 字母k, 有dp[k][ j-i+1 - (sum[k][j]-sum[k][i-1]) ] = max(dp[k][ j-i+1 - (sum[k][j]-sum[k][i-1]) ], j-i+1);
(j-i+1 - (sum[k][j]-sum[k][i-1])
表示在区间[i, j]中, 要把区间全部填成字母k, 需要改变的字符数量)
两重循环处理完所有区间[i, j]后, dp数组还有一些值没有更新过, 一直为零
同时, 如果更改i个字母得到最长只含有字符j的子串长度为len, 那么更改i+1个能得到的子串长度一定大于等于len+1, dp[j][i] = max(dp[j][i], dp[j][i-1]+1);
, 这个很容易理解
最后dp的值不能大于n
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 2000;
int n, q, dp[30][MAXN], sum[30][MAXN], m;
char s[MAXN], col[20];
int main()
{
scanf("%d%s", &n, s+1);
for(int i=1; i<=n; ++i)
{
for(int j=0; j<26; ++j)
sum[j][i] = sum[j][i-1];
sum[s[i]-'a'][i] += 1;
}
memset(dp, 0, sizeof(dp));
for(int i=1; i<=n; ++i)
{
for(int j=i; j<=n; ++j)
{
for(int k=0; k<26; ++k)
{
dp[k][ j-i+1 - (sum[k][j]-sum[k][i-1]) ]
= max(dp[k][ j-i+1 - (sum[k][j]-sum[k][i-1]) ], j-i+1);
}
}
}
for(int i=1; i<=n; ++i)
for(int j=0; j<26; ++j) dp[j][i] = max(dp[j][i], dp[j][i-1]+1);
scanf("%d", &q);
for(int i=0; i<q; ++i)
{
scanf("%d%s", &m, col);
printf("%d\n", dp[col[0]-'a'][m] > n ? n : dp[col[0]-'a'][m]);
}
return 0;
}