字符串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]);
}
}
}