发糖果问题——二分、贪心

注:与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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值