题面传送门

原题题号:Codeforces 883D

题意:

有 \(n\) 个位置,每个位置上要么有一条狗,要么有一根骨头,要么啥都没有。

现在你要给每个狗指定一个方向(朝左或朝右)。

朝左的狗可以到达它左边的所有位置,朝右的狗可以到达它右边的所有位置。它们的速度均为 \(1\) 格\(/s\)

如果一个格子上有骨头,那么最先到达这个格子上的狗可以吃掉这个骨头。

求最多能吃掉多少个骨头,以及最少需要多长时间才能达到这个局面。

\(n \in [1,10^5]\)

显然,如果只有 \(1\) 只狗,那么就暴力枚举它朝左还是朝右,然后取个 \(\max\) 即可。

如果有 \(2\) 只狗及以上,那么所有骨头都能被吃掉。

难点在于第二问。考虑二分答案 \(x\),需检查在 \(x\) 秒内这些狗能否吃掉所有骨头。

假设第 \(i\) 只狗的位置为 \(p_i\),那么这只狗要么吃掉 \([p_i-x,p_i]\) 之间的骨头,要么吃掉 \([p_i,p_i+x]\) 之间的骨头。

考虑 \(dp\)。\(dp_i=j\) 表示按位置从小到大排序,第 \(1\) 到第 \(i\) 只狗最多能吃掉前 \(j\) 个位置上的所有骨头。

你再预处理 \(s_i\),\(s_i\) 表示位置 \(1\) 到 \(i\) 总共多少个骨头。

分三种情况:

  1. 第 \(i\) 只狗向左走,也就是 \([p_i-x,p_i]\) 中有骨头没有被吃掉。这种情况满足的条件是前 \(i-1\) 只狗能够吃完 \([1,p_i-x-1)\) 中的所有骨头,也就是 \(dp_{i-1} \geq p_i-x\) 或 \(s_{p_i-x-1}=s_{dp_{i-1}}\),i.e. \((dp_{i-1},p_i-x-1)\) 中没有骨头,并更新 \(dp_i=\max(dp_i,p_i)\)。
  2. 第 \(i\) 只狗向右走。这种情况的满足条件是 \([1,p_i)\) 中所有骨头都被前 \(i-1\) 条狗吃掉。也就是 \(dp_{i-1} \geq p_i\) 或 \(s_{p_i-1}=s_{dp_{i-1}}\),并更新 \(dp_i=\max(dp_i,p_i+x)\)。
  3. 第 \(i\) 只狗向左走,第 \(i-1\) 只狗向右走。这种情况的满足条件是 \([p_{i-1},p_{i-1}+x]\cup[p_i-x,p_i]\) 可以包含 \([p_{i-1},p_i]\) 中所有骨头,并且 \(dp_{i-2} \geq p_{i-1}\) 或 \(s_{p_{i-1}-1}=s_{dp_{i-2}}\),并更新 \(dp_i=\max(dp_i,\max(p_i,p_{i-1}+x))\)

    为什么这三种情况能涵盖所有情况呢?

    考虑一只向右走的狗。显然它前面所有骨头都被吃掉了,要么是被它左边的狗吃掉了(情况 2),要么是被它右边的狗吃掉了(情况 3)。

    再考虑一只向左走的狗,根据上面的推论 \([1,p_i-x)\) 所有骨头都被吃掉了。而这些骨头只能被它左边的狗吃掉,所以只有 1 种情况,也就是情况 1。
/*
Contest: -
Problem: NFLSOJ 712
Author: tzc_wk
Time: 2020.10.20
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
int n;char s[1000005];
int posd[1000005],cntd=0;
int posb[1000005],cntb=0;
int dp[1000005];
int hav[1000005];
inline bool check(int mid){
memset(dp,0,sizeof(dp));
for(int i=1;i<=cntd;i++){
if(dp[i-1]>=posd[i]||hav[posd[i]-1]==hav[dp[i-1]]) dp[i]=max(dp[i],posd[i]+mid);
if(dp[i-1]>=posd[i]-mid||hav[posd[i]-mid-1]==hav[dp[i-1]]) dp[i]=max(dp[i],posd[i]);
else return 0;
if(i>=2&&(posd[i-1]+mid>=posd[i]-mid||hav[posd[i-1]+mid]==hav[posd[i]-mid-1])&&(dp[i-2]>=min(posd[i-1],posd[i]-mid)||hav[dp[i-2]]==hav[min(posd[i-1],posd[i]-mid)-1]))
dp[i]=max(dp[i],max(posd[i],posd[i-1]+mid));
dp[i]=min(dp[i],n);
// printf("%d %d\n",i,dp[i]);
}
if(hav[dp[cntd]]==hav[n]) return 1;
return 0;
}
int main(){
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++) if(s[i]=='D') posd[++cntd]=i;
for(int i=1;i<=n;i++) if(s[i]=='B') posb[++cntb]=i;
posb[cntb+1]=n+1;
for(int i=0;i<=cntb;i++){
for(int j=posb[i];j<posb[i+1];j++) hav[j]=i;
}
if(cntd==1){
int cntl=0,cntr=0,mxl=0,mxr=0;
for(int i=1;i<=posd[1];i++) if(s[i]=='B') cntl++,mxl=max(mxl,posd[1]-i);
for(int i=posd[1];i<=n;i++) if(s[i]=='B') cntr++,mxr=max(mxr,i-posd[1]);
if(cntl>cntr) printf("%d %d\n",cntl,mxl);
else if(cntr>cntl) printf("%d %d\n",cntr,mxr);
else printf("%d %d\n",cntl,min(mxl,mxr));
return 0;
}
// check(4);
int l=1,r=n,ans=-23987;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d %d\n",cntb,ans);
return 0;
}

【2020五校联考NOIP #8】狗的更多相关文章

  1. 【2020五校联考NOIP #6】三格缩进

    题意: 给出 \(n\) 个数 \(a_1,a_2,\dots,a_n\),你要进行 \(m\) 次操作,每次操作有两种类型: \(1\ p\ x\):将 \(a_p\) 改为 \(x\). \(2\ ...

  2. 【2020五校联考NOIP #8】自闭

    题目传送门 题意: 有一个 \(n \times m\) 的矩阵,里面已经填好了 \(k\) 个非负整数. 问是否能在其它 \(n \times m-k\) 个格子里各填上一个非负整数,使得得到的矩阵 ...

  3. 【2020五校联考NOIP #7】道路扩建

    题面传送门 题意: 给出一张 \(n\) 个点 \(m\) 条边的无向图 \(G\),第 \(i\) 条边连接 \(u_i,v_i\) 两个点,权值为 \(w_i\). 你可以进行以下操作一次: 选择 ...

  4. 【2020五校联考NOIP #4】今天的你依旧闪耀

    题面传送门 题意: 对于一个长度为 \(n\)(\(n\) 为偶数)的排列 \(p\),定义一次"变换"后得到的排列 \(p'\) 为: \(p'_i=\begin{cases}p ...

  5. 【2020五校联考NOIP #3】序列

    题面传送门 原题题号:Codeforces Gym 101821B 题意: 给出一个排列 \(p\),要你找出一个最长上升子序列(LIS)和一个最长下降子序列(LDS),满足它们没有公共元素.或告知无 ...

  6. 【2020五校联考NOIP #7】伟大的卫国战争

    题面传送门 题意: 数轴上有 \(n\) 个点,现在要在它们之间连 \(m\) 条边,第 \(i\) 条边连接 \(a_i,b_i\) 两个点. 现在你要钦定每条边连在数轴的上方还是下方,使得任意两条 ...

  7. 【2020五校联考NOIP #6】最佳观影

    题意: 给出一个 \(k \times k\) 的网格和 \(n\) 次操作.其中 \(k\) 为奇数. 每次操作给出一个数 \(m\).每次你要找出一个三元组 \((x,l,r)\) 使得: \(r ...

  8. 【2020五校联考NOIP #2】矩阵

    咕咕咕到现在~ 题面传送门 题意: 给出一个 \(n\times n\) 的矩阵 \(A\).要你求有多少个 \(n\times n\) 的矩阵 \(B\) 满足: 每一行都是 \(1\) 到 \(n ...

  9. 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你

    [五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...

随机推荐

  1. Vulnhub实战-grotesque3靶机👻

    Vulnhub实战-grotesque3靶机 靶机地址:http://www.vulnhub.com/entry/grotesque-301,723/ 1.靶机描述 2.主机探测,端口扫描 我们在vm ...

  2. 《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)

    1.简介 在实际自动化测试过程中,我们同样也避免不了会遇到单选和多选的测试,特别是调查问卷或者是答题系统中会经常碰到.因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助 ...

  3. 【Spring】IoC容器 - 依赖来源

    前言 上一篇文章已经学习了[依赖注入]相关的知识,这里详细的介绍一下[依赖来源]. 依赖来源 我们把依赖来源分为依赖查找的来源和依赖注入的来源分别讨论. 依赖查找的来源 1. Spring BeanD ...

  4. Spring Cloud Gateway 网关限流

    Spring Cloud Gateway 限流 一.背景 二.实现功能 三.网关层限流 1.使用默认的redis来限流 1.引入jar包 2.编写配置文件 3.网关正常响应 4.网关限流响应 2.自定 ...

  5. spring cache整合redis

    在项目中,我们经常需要将一些常用的数据使用缓存起来,避免频繁的查询数据库造成效率低下.spring 为我们提供了一套基于注解的缓存实现,方便我们实际的开发.我们可以扩展spring的cache接口以达 ...

  6. spring social理解

    现在互联网飞速发展,人们每天在互联网上冲浪,获取各种信息.各大网站为了方便用户的登录,提供了各式各样的社交登录,比如:QQ.微信和微博登录等.这些主流的社交登录大多是基于oauth协议进行实现,spr ...

  7. C/C++编程笔记:浪漫流星雨表白装b程序

    作为一个未来可能会成为一个专业程序员的小伙们,不知道你们现在学到哪里了,学了点东西之后有没有想在你女朋友面前装个大大的b呢,今天小编就给你一个机会来研究一下下边的代码吧,保证大写的N,当然大佬是排除在 ...

  8. 零基础小白要如何跟好的学习嵌入式Linux

    作为一个新人,怎样学习嵌入式Linux?被问过太多次,特写这篇文章来回答一下. 在学习嵌入式Linux之前,肯定要有C语言基础.汇编基础有没有无所谓(就那么几条汇编指令,用到了一看就会). C语言要学 ...

  9. Oracle 11g 常用sql记录

    --表备份 create table xxx_bak as select * from xxx; --表数据清除 truncate table xxx --锁表问题处理sql开始 select ses ...

  10. 它说你的代码有 Bug「GitHub 热点速览 v.21.44」

    作者:HelloGitHub-小鱼干 本周热点上的榜单大多数提升工作效率的实用工具,像是一个 API 管理所有通知消息(包括推送.邮件-)的 notifire,再是高速解析 JSON 文件的 simd ...