CF D. Packmen Strike Back

24 篇文章 0 订阅

题意

给你一个长度为n的字符串
.表示空地
*表示豆子
P表示吃豆子的人
问你所有吃豆人所可以吃到最多的豆子是多少,且输出最少时间

题解

一个人就直接枚举方向就可以了
如果有两个人,那么他们一定可以把所有豆子吃完
问你就变成了要把所有豆子吃完要多少时间
直接做不好做
考虑二分一个答案
f[i]表示前i个人所可以吃到最右边的豆子,当然,不能漏
那么有三种转移
1.第i个人往右走
2.第i个人往左走
3.第i个人往左走,第i-1个人往右走
分别讨论进行转移就可以了

CODE:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1000005;
int n;
char ss[N];
int a[N];
int p[N],tot=0;
int f[N];//q个人所可以覆盖到的最远是多少 
bool ok (int l,int r)//这一段区间是不是没有豆子了 
{
    if (l>r) return true;
    return a[r]-a[l-1]<=0;
}
bool check (int x)
{
    memset(f,0,sizeof(f));
    for (int u=1;u<=tot;u++)//这一个人 
    {
        //这个人往左走
        if (ok(f[u-1]+1,p[u]-x-1)) f[u]=max(f[u],p[u]);
        //这个人往右走 
        if (ok(f[u-1]+1,p[u]-1)) f[u]=max(f[u],p[u]+x);
        //这个人往左走,另外一个往右走
        if (u>1)
        {
            if (ok(f[u-2]+1,p[u]-x-1)) f[u]=max(f[u],p[u-1]+x);
        }
    //  printf("%d ",f[u]);
    }
    return ok(f[tot]+1,n);
}
int main()
{
    scanf("%d",&n);
    scanf("%s",ss+1);
    a[0]=0;
    for (int u=1;u<=n;u++) a[u]=a[u-1]+(ss[u]=='*');
//  printf("YES");
    for (int u=1;u<=n;u++)
        if (ss[u]=='P')
            p[++tot]=u;
    if (tot==1)
    {
        int p1=a[p[tot]],p2=a[n]-a[p[tot]];
        int c1=p[1]-1,c2=n-p[1];
        for (int u=1;u<p[1];u++)
            if (ss[u]=='.') c1--;
            else break;
        for (int u=n;u>p[1];u--)
            if (ss[u]=='.')  c2--;
            else break;
        if (p1>p2||(p1==p2&&c1<c2))
            printf("%d %d\n",p1,c1);
        else
            printf("%d %d\n",p2,c2);
    }
    else
    {
        printf("%d ",a[n]);
        int l=1,r=n;
        int ans=0;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (check(mid)) {ans=mid;r=mid-1;}
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值