loj 恋爱循环

字符串s对于字符c的权值,定义为s中仅由c组成的最长连续子串的长度。例如,对于 s=kooomio,其由字符o组成的最长连续子串为ooo,因此它对于字符o的权值为3。

给定由小写字母组成的字符串s以及q个询问。每个询问形如 (mi,ci),表示「求出在s中至多更改mi个位置的字符后所得的字符串s′对于字符ci的最大权值」。


输入描述:

多组数据每组输入的第一行包含一个正整数n——字符串s的长度。第二行包含n个小写英文字母组成的字符串s1 s2 …sn——给定的初始字符串。第三行包含一个正整数q——询问的数目。接下来q行,每行包含一个正整数mi ——至多在s中更改的字符数目,和以一个空格分隔的小写字母ci——计算权值时使用的字符。

输出描述:

每组输出q行:对于每个询问输出一行,包含一个整数——进行更改后所得字符串s′的最大权值。

样例输入:

复制
6
koyomi
3
1 o
4 o
4 m

样例输出:

365

提示:

样例解释

在样例中,有三个询问:

在第一个询问中,最多可以更改s一个位置上的字符,将y所处的位置改为o得到s′=kooomi,权值为3;

在第二个询问中,最多可以更改s四个位置上的字符,s′=oooooo的权值为6;

在第三个询问中,最多可以更改s四个位置上的字符,s′=mmmmmi 和 s′=kmmmmm 的权值均为5。

数据范围与提示

1≤n≤1500

1≤q≤200000

1≤mi≤n,ci为小写英文字母

解 : 把所有的情况先存入数组 o(1)查询,   

#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#include<queue>
#include<deque>
#include<math.h>
#define ll long long
const int inf=1e9;
using namespace std;
int d[30][1600];//代表改变第i字母 改变j 次  能获得的最长长度   
int p[1600];
int v[30];//是否出现过
int tot=0;
struct node
{
    int u,next,k;//u代表位置,k代表第几个
}e[200000];
void add(int u,int x)
{
    e[tot].u=x;
    e[tot].next=p[u];
    e[tot].k=(p[u]==-1)?1:e[p[u]].k+1;//如果p[u]为-1 代表他是第一个 ,否则就是上一个+1
    p[u]=tot++;
}
void init()
{
    tot=0;
    memset(p,-1,sizeof(p));
    memset(d,0,sizeof(d));
    memset(v,0,sizeof(v));
}
char s[1600];
int main()
{
    int n,q;
    while(~scanf("%d",&n))
    {
        scanf("%s",s);
        init();
        for(int i=0;i<n;i++)
        {
            add(s[i]-'a',i);
            v[s[i]-'a']=1;//标记出现
        }
        for(int i=0;i<26;i++)//枚举26个字母
        {
            if(v[i]) d[i][0]=1;//如果被标记 ,那么代表改变0个也至少有1个
            for(int j=p[i];j+1;j=e[j].next)//枚举所有为该字母的点
            {
                for(int k=e[j].next;k+1;k=e[k].next)//枚举在这个点之前的所有点
                {
                    int aa=(e[j].u-e[k].u)-(e[j].k-e[k].k);//最小要改变的东西
                     int bb=e[j].u-e[k].u+1;//改变后的长度
                    d[i][aa]=max(d[i][aa],bb);//取最大的
                }
            }
        }
        for(int i=0;i<26;i++)
            for(int j=1;j<=1500;j++)
                d[i][j]=min(n,max(d[i][j],d[i][j-1]+1));//最大也只有n   ,如果d[i][j]在上次枚举时没有出现,那么就是d[i][j-1]+1 ,上一个最长的长度+1



        scanf("%d",&q);
        int uu;
        char ff;
        while(q--)
        {
        scanf("%d %c",&uu,&ff);
        printf("%d\n",d[ff-'a'][uu]);
        }
    }

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值