//yy:因为这题多组数据,DP预处理存储状态比每次尺取快多了,但是我更喜欢这个尺取的思想。
题目链接:codeforces 814 C. An impassioned circulation of affection
题意:给出字符串长度n (1 ≤ n ≤ 1 500),字符串s由小写字母组成,q个询问q (1 ≤ q ≤ 200 000),每个询问为:mi (1 ≤ mi ≤ n) ci ,表示可以把任意mi个字母改成ci,求每次改变后只由ci组成的最长连续字串的长度。
解法一:尺取法:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = +;
char s[N];
char c;
int n, q, m;
int main() {
scanf("%d %s", &n, s);
scanf("%d", &q);
while(q--) {
scanf("%d %c", &m, &c);
int l = , r = ;
int ans = ;
int cnt = ;
while(r < n) {
if(cnt <= m) {
if(s[r++] != c) cnt++;
}
if(cnt > m) {
if(s[l++] != c) cnt--;
}
ans = max(ans, r - l);
}
printf("%d\n", ans);
}
return ;
}
997ms
解法二:DP:打个表,暴力枚举区间,求区间内字母i没有出现的个数j,然后dp[i][j]表示换成j个字母i所求的最长长度,每次询问直接输出即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = ;
int dp[][N];
char s[N], c;
int n, q, i, j, k, num, m;
int main() {
scanf("%d %s %d", &n, s+, &q);
for(k = ; k < ; ++k) {
for(i = ; i <= n ; ++i) {
num = ;
for(j = i; j <= n; ++j) {
if(s[j]-'a' != k) num++;
dp[k][num] = max(dp[k][num], j-i+);
}
}
for(i = ; i <= n; ++i)
dp[k][i] = max(dp[k][i], dp[k][i-]);
}
while(q--) {
scanf("%d %c", &m, &c);
printf("%d\n", dp[c-'a'][m]);
}
return ;
}
156ms
解法三:还是DP。。。yy无聊打发时间。。。发呆
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = ;
int dp[][N];
char s[N], c;
int n, q, i, j, k, num, m;
int main() {
scanf("%d %s %d", &n, s+, &q);
for(i = ; i < ; ++i)
for(j = ; j <= n; ++j) dp[i][j] = j;
for(i = ; i <= n; ++i) {
for(num = , j = i; j <= n; ++j) {
if(s[j] != s[i]) num++;
if(j-i+ > dp[s[i]-'a'][num]) dp[s[i]-'a'][num] = j-i+;
}
}
for(i = ; i <= n; ++i) {
for(num = , j = n; j >= ; --j) {
if(s[j] != s[i]) num++;
if(n-j+ > dp[s[i]-'a'][num]) dp[s[i]-'a'][num] = n-j+;
}
}
for(i = ; i < ; ++i)
for(j = ; j <= n; ++j)
dp[i][j] = max(dp[i][j], dp[i][j-]);
/*for(i = 0; i < 26; ++i)
for(j = 1;j <= n; ++j)
printf("%d\t", dp[i][j]);
puts("");*/
while(q--) {
scanf("%d %c", &m, &c);
printf("%d\n", dp[c-'a'][m]);
}
return ;
}
109ms