Codeforces Round #418 (Div. 2) 814 C. An impassioned circulation of affection

题目大意

给你一个长度为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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值