1 条题解
-
0
自动搬运
来自洛谷,原作者为

ReseeCher
AFO·运气选手搬运于
2025-08-24 22:22:36,当前版本为作者最后更新于2020-07-01 21:52:36,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
约定覆盖位置,,......的为一条从开始的
“直线”约定覆盖位置,,......的为一条从开始的
“跳线”那么原问题相当于使用一些直线和跳线使每个位置刚好被条线覆盖
每用一条线称作个,我们希望总的最小
首先考虑如何去覆盖第和第个位置
为了方便,这里表示位置还要被几条线段覆盖
这里先给出方案:
-
:从开始一条跳线
-
:从开始一条直线
-
:暂时不决策
比较显然,位置已经不能被覆盖,只能连出跳线
考虑证明以下命题:
从1开始的连续非0区间(长度>=2)用一条直线覆盖一定不劣设这段区间为,那么因为,所以不可能向后连出直线,唯一有利于后面位置被覆盖的方案是在与奇偶性相同的位置连出一条跳线
但是这样做必有,而使用一条直线和一条跳线为,所以一定不优于原方案(不如从后面开始跳线)
此时由于了,我们可以把位置删除,继续考虑第和第个位置
这个问题与刚才的问题类似,唯一的区别是要处理被前面开始的线覆盖的情况
如果能被前面的线覆盖则一定被覆盖,因为这样,而任意一种可能更利于后面被覆盖的方案都需要,不如从后面开始
若前面的直线有个,能连到的跳线有个
那么如果,直接把减去即可
但如果,则一定有条线无法连下去,记为
发现保留直线还是跳线和后面的位置有关,于是我们可以先把A和B都减去,再在上打个标记,表示可以从免费开始条任意的线
但这时候出现了一个新的问题,和不能被减到负数
注意到若,那么至少也要断掉条,那么先把这些边断掉,这样就没有问题了
时同理
这样我们就有一个可以从推到的算法了,一遍推过去即可
具体可以看代码中的注释
void Work(){ LL A=0,B=0,C=0,Ans=0,D=0; //C表示奇偶性为另一类的跳线个数 F(i,2,n+1){ if(a[i]<B+A){ //处理被前面的线覆盖的情况 int K=B+A-a[i]; if(B<K)A-=K-B,K-=K-B; if(A<K)B-=K-A,K-=K-A; B-=K;A-=K;a[i]-=K;D=K; //D:记录标记个数 } a[i]-=A+B; LL U=min(a[i-1],a[i]); //U:新增直线个数 Ans+=U;a[i-1]-=U;a[i]-=U;A+=U; //处理直线 Ans+=a[i-1];C+=a[i-1];a[i-1]=0; //处理跳线 a[i]+=D;Ans-=D;D=0; //处理标记 swap(B,C); //奇偶性互换 } cout<<Ans<<'\n'; } -
- 1
信息
- ID
- 5678
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者