注:与CF上的Sweets for Everyone!不一样
几个关键点:
1.刚开始的位置是0。
2.在时间充裕的前提下,如果手上的糖不够,可以路过H不发糖,去S买了回来再发。
3.但是每个S只能买一次糖。
4.如果时间t内不能给所有邻居发完糖果,则输出-1。
5.为了刚开始带最少的糖果,每经过一个S一定买糖果。
误解:刚开始以为不能走回头路
代码如下:
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <vector>
using namespace std;
const int maxn=1e5+100;
int N,T;
char s[maxn];
bool check(int num) //num为当前手中的糖果
{
int sum[maxn];
int L[maxn],R[maxn];
stack<int> st;
int m=0,time=0;
while(!st.empty()) st.pop();
for(int i =1;i<=N;i++)
{
if(s[i]=='H')
{
if(num==0) //如果没有糖果了,入栈
st.push(i);
else
num--; //否则手中的糖果数减1
time=i;
}
else if(s[i]=='S')
{
if(st.size()>0)
{
if(st.size()==1)
{
L[++m]=st.top();
R[m]=i;
}
st.pop();
time=i;
}
else // 如果前面的H都已经发完糖果,则遇到S一定买糖果
num++;
}
}
if(st.size()>0) return false; //如果糖果不够,直接返回
if(m==0) return time<=T; //如果无需往返,则直接判断时间
sum[0]=0;
for(int i =1;i<=m;i++)
sum[i]=(R[i]-L[i])*2 + sum[i-1]; //前i段重复两边的总时间
int ans=time+sum[m]; //全程重复两遍的总时间
for(int i=1;i<=m;i++)
ans = min(ans,time+sum[i-1]+time-L[i]); //前i段重复一遍从第i段起重复一遍的总时间
return ans<=T;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&N,&T);
scanf("%s",s+1);
int left=-1,right=N;
if(!check(right)) right=-1;
while(left+1<right)
{
int mid=(left+right)>>1;
check(mid) ? right=mid : left=mid;
}
printf("%d\n",right);
}
return 0;
}