【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 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...
随机推荐
- Linux服务器装Anaconda&TensorFlow
远程Linux服务器装Anaconda&指定版本TensorFlow 说明: 由于疫情影响,原先使用的服务器已断电,故重选了一台服务器对环境重选进行搭建,正好补上这篇博文. 01 下载Anac ...
- Java编程开发学习路线图(附所有免费课程+在线自测)
转自 https://yq.aliyun.com/articles/134286?spm=5176.100239.0.0.1UfveS 摘要: 长期以来,Java一直占据TIOBE编程语言排行版第一 ...
- 好好编程BUAA_SE(组/团队) Scrum Meeting 博客汇总
好好编程BUAA_SE(组/团队) Scrum Meeting 博客汇总 一.Scrum Meeting 1. Alpha Alpha阶段 第一次Scrum Meeting Alpha阶段 第二次Sc ...
- elasticsearch使用ik中文分词器
elasticsearch使用ik中文分词器 一.背景 二.安装 ik 分词器 1.从 github 上找到和本次 es 版本匹配上的 分词器 2.使用 es 自带的插件管理 elasticsearc ...
- CF #749
A 题意 有个长度为n的序列, 每个数互不相同, 求总和最大的最长子序列, 并输出每个i: 题解 emmmmmm, 刚开始看到这个数据和题解被迷惑了, 以为有什么顺序, 并且一直在想一些复杂度较高的算 ...
- JAVA笔记7__接口应用/Object类/简单工厂模式/静态代理模式/适配器模式
/** * 接口应用 */ public class Main { public static void main(String[] args) { Person p = new Person(&qu ...
- cf Make It Nondeterministic (简单贪心)
有N个人.每个人都有两个名字. 给出这N个人的一个排列.p[1]...p[N]. 现在让每个人挑自己丙个名字中的一个名字.问是否存在一种方案,使得挑出来的N个名字按字典序排完以后正好是p[1]...p ...
- Python技法4:闭包
闭包:用函数代替类 有时我们会定义只有一个方法(除了__init__()之外)的类,而这种类可以通过使用闭包(closure)来替代.闭包是被外层函数包围的内层函数,它能够获取外层函数范围中的变量(即 ...
- 应对gitee容量超限. 保留star/fork/评论
应对gitee容量超限 进入企业版,"管理"-"仓库管理",点"清空仓库". 在E:\gitee目录上右击,"git bash h ...
- spark搭建
1.上传解压,配置环境变量 配置bin目录 2.修改配置文件 conf cp spark-env.sh.template spark-env.sh 增加配置 export SPARK_MASTER_I ...