传送门:codeforces 834B
题目大意:
有 A~Z 共26扇门,有 n 个人要依次从指定的门进入,每扇门在该门进入的第一个人之前开启,在该门进入的最后一人进入后关闭,之间一直开着,问有 k 个守卫是否可以保证每一时刻每扇开着的门都有守卫看守。
思路:
找到每扇门第一个和最后一个人进入的时间,解法类似于坐火车选坐车区间,问火车最少需要准备多少个座位的题。这种题的一种解法是将每扇门的开始时间对应的点设为 1,结束时间对应的点设为 -1,其他点为 0,然后扫描一遍将这些值相加,取最大值。
但是这样会出现一个问题,如 ABCBA 这组样例,最少需要 3 个守卫,但是 C 是只有一个,这时候可以开两倍的空间,对单个字母特殊处理即可。
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
using namespace std;
int vis[2000010];
int main()
{
int i,n,k,f,sz,ans,num;
char s[1000010];
vector<int> pos[28]; //保存每扇门人经过的时间
while(~scanf("%d%d",&n,&k))
{
scanf("%s",s);
memset(vis,0,sizeof(vis));
for(i=0;i<=26;i++) pos[i].clear();
for(i=0;i<n;i++) //将每个人放入对应的门中
pos[s[i]-'A'].push_back(i);
f=0;
for(i=0;i<=26;i++)
{ //扫描每个门
sz=pos[i].size();
if(sz==1)
{ //如果该门只有一个人经过
f=1;
vis[pos[i][0]*2]=1; //开始点设为 1
vis[pos[i][0]*2+1]=-1; //结束点设为 -1
}
if(sz>1)
{
vis[pos[i][0]*2]=1; //开始点设为 1
vis[pos[i][sz-1]*2]=-1; //结束点设为 -1
}
}
num=0;
ans=f;
for(i=0;i<n*2;i++)
{ //扫描一遍取最大值
num+=vis[i];
if(num>ans) ans=num;
}
// printf("ans=%d\n",ans);
if(ans>k) printf("YES\n");
else printf("NO\n");
}
return 0;
}