1912: 小火山的爱情密码
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 246 Solved: 64
SubmitStatusWeb Board
Description
小火山获得了一个字符串,然而大火山让小火山从里面截取一段字符串,并且让小火山截取的字符串满足一些字符达到一定数量。
小火山觉得很容易,但是他想要知道他至少得截取多长的字符串。
Input
首先是一个整数t(t<=100),表示测试数据组数。接下来是两个整数n和m(n<=10000, m<=10),n表示字符串的长度,m表示要满足一定数量的字符
的种类.(字符只包含小写英文字母)
个数(没有重复字符种类),然后有m行,每行第一个是一个字符,然后是一个整数x(x<=50),表示这种字符的的要求数量。
Output
输出最小长度,如果达不到要求输出-1
Sample Input
1
6 3
cancan
c 2
a 2
n 2
Sample Output
6
- 题意:给一个长N的字符串,有对M个字符的数量要求,求满足要求的最短子串的长度;
- 思路:这题和POJ-3302超级像,只是多了个字符的数量要求,而那一题只是对字符种类的要求,因此此题在那一题的基础之上再加一个条件判断即可,就是将遇到一类字符++sum改成遇到要求数量的字符时++sum;
- 失误:过了真不容易,提心吊胆的,总怕又wa了,主要的错误就是那个判断什么时候sum加的解决和不满足要求时的方法,做的这几道尺取都能用二分,可惜我现在还想不出来。
- 代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int MAXN=1e6;
char str[MAXN];
int main()//main打错编译出来什么WIN@16啥的
{
int N,T,M,i,sum,lsub,R,L,ans,tem; char ch;
scanf("%d",&T);
while(T--)
{
map<char,int> MP,S;
scanf("%d %d",&N,&M);
scanf("%s",str+1);
for(i=1;i<=M;++i)
{
getchar();//如果自己的测试数据最后没有换行 调试会卡到这 知道你输入换行
scanf("%c %d",&ch,&tem);
MP[ch]=tem;
}
L=1; R=1; ans=N; sum=0; lsub=0; bool flag=false,K=false;
while(R<=N)
{
while(R<=N&&sum<M)
{
++S[str[R]];//下面的条件很关键 >=一个字符会加多次
if(S[str[R]]==MP[str[R]]&&MP[str[R]]) ++sum;//读取的字符必须是要求的字符
++R; ++lsub;
}
if(sum<M&&!K)//有两种不服合要求:要求的字符串中没有 要求的都有但长度不够
{
flag=true; break;//如果有这两种情况 程序进行一次就该结束
}
while(sum==M)
{
--S[str[L]];
if(S[str[L]]<MP[str[L]]&&MP[str[L]]) --sum;
++L; --lsub;
}
ans=min(ans,lsub+1);
K=true;//如果为真 那么肯定有符合要求的子串
}
if(flag) printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}