【2020五校联考NOIP #8】狗
题面传送门
原题题号: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\) 总共多少个骨头。
分三种情况:
- 第 \(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)\)。
- 第 \(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)\)。
- 第 \(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】狗的更多相关文章
- 【2020五校联考NOIP #6】三格缩进
题意: 给出 \(n\) 个数 \(a_1,a_2,\dots,a_n\),你要进行 \(m\) 次操作,每次操作有两种类型: \(1\ p\ x\):将 \(a_p\) 改为 \(x\). \(2\ ...
- 【2020五校联考NOIP #8】自闭
题目传送门 题意: 有一个 \(n \times m\) 的矩阵,里面已经填好了 \(k\) 个非负整数. 问是否能在其它 \(n \times m-k\) 个格子里各填上一个非负整数,使得得到的矩阵 ...
- 【2020五校联考NOIP #7】道路扩建
题面传送门 题意: 给出一张 \(n\) 个点 \(m\) 条边的无向图 \(G\),第 \(i\) 条边连接 \(u_i,v_i\) 两个点,权值为 \(w_i\). 你可以进行以下操作一次: 选择 ...
- 【2020五校联考NOIP #4】今天的你依旧闪耀
题面传送门 题意: 对于一个长度为 \(n\)(\(n\) 为偶数)的排列 \(p\),定义一次"变换"后得到的排列 \(p'\) 为: \(p'_i=\begin{cases}p ...
- 【2020五校联考NOIP #3】序列
题面传送门 原题题号:Codeforces Gym 101821B 题意: 给出一个排列 \(p\),要你找出一个最长上升子序列(LIS)和一个最长下降子序列(LDS),满足它们没有公共元素.或告知无 ...
- 【2020五校联考NOIP #7】伟大的卫国战争
题面传送门 题意: 数轴上有 \(n\) 个点,现在要在它们之间连 \(m\) 条边,第 \(i\) 条边连接 \(a_i,b_i\) 两个点. 现在你要钦定每条边连在数轴的上方还是下方,使得任意两条 ...
- 【2020五校联考NOIP #6】最佳观影
题意: 给出一个 \(k \times k\) 的网格和 \(n\) 次操作.其中 \(k\) 为奇数. 每次操作给出一个数 \(m\).每次你要找出一个三元组 \((x,l,r)\) 使得: \(r ...
- 【2020五校联考NOIP #2】矩阵
咕咕咕到现在~ 题面传送门 题意: 给出一个 \(n\times n\) 的矩阵 \(A\).要你求有多少个 \(n\times n\) 的矩阵 \(B\) 满足: 每一行都是 \(1\) 到 \(n ...
- 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你
[五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...
随机推荐
- SpringCloud-SpringBoot-SpringCloudAlibaba对应版本选择
一.SpringCloud-SpringBoot 对应的版本选择 SpringCloud官网常规方式只能查看最新的几个版本信息 https://spring.io/projects/spring-cl ...
- 单片机STM32开发中常用库函数分析
1.GPIO初始化函数 用法: voidGPIO_Configuration(void) { GPIO_InitTypeDefGPIO_InitStructure;//GPIO状态恢复默认参数 GPI ...
- Oracle 11g 新建用户
create user XXXuser identified by XXXpassword;--创建用户XXXuser,设置初始密码XXXpassword alter user XXXuser ide ...
- 数值的整数次方 牛客网 剑指Offer
数值的整数次方 牛客网 剑指Offer 题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方 class Solution: #run ...
- 二叉树中和为某一值的路径 牛客网 程序员面试金典 C++ Python
二叉树中和为某一值的路径 牛客网 程序员面试金典 题目描述 输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一 ...
- hdu 5092 Seam Carving (简单数塔DP,题没读懂,,不过可以分析样例)
题意: 给一个m*n的矩阵,每格上有一个数. 找从第1行到第m行的一条路径,使得这条路径上的数之和最小. 路径必须满足相邻两行所选的两个数的纵坐标相邻(即一个格子必须是另一个格子的周围八个格子中的一个 ...
- Vue3.x 关于组件的那些变化(新手必看篇)
一.组件内的 data 为什么总是函数形式? 我们试着先做一个计数器案例,把 data 的返回形式修改成一个对象.具体的代码如下: <template> <div> <b ...
- QuantumTunnel:Netty实现
接上一篇文章内网穿透服务设计挖的坑,本篇来聊一下内网穿透的实现. 为了方便理解,我们先统一定义使用到的名词: UserClient:用户客户端,真实的请求发起方: UserServer:内网穿透-用户 ...
- Ubuntu 安装 mysql 报错 "update-alternatives: 错误: 候选项路径 /etc/mysql/mysql.cnf 不存在"
解决方法: sudo cp /etc/mysql/my.cnf /etc/mysql/mysql.cnf 偷梁换柱-! 如果想更新mysql的源方法如下: wget http://dev.mysql. ...
- RabbitMQ的安装及入门使(Windows)
1.安装Erlang所以在安装rabbitMQ之前,需要先安装Erlang .点击下载Erlang 执行下载下来的Erlang,全部点击"下一步"就行.安装完成设置一下环境变量. ...