The 2021 Sichuan Provincial Collegiate Programming Contest J.Ants(思维题/模拟)

题目

n(1<=n<=1e6)只蚂蚁,在一根杆上,杆左端点0,右端点1e9+1,

n只蚂蚁第i只的初始位置在ai,输入保证a_{i}<a_{i+1}

di=0代表当前向左爬,di=1代表当前向右爬

左端点有一个柱子,被撞a(1<=a<=1e9)次后消失,被撞<=a次的时候都会把蚂蚁往反方向弹

右端点有一个柱子,被撞b(1<=b<=1e9)次后消失,被撞<=b次的时候都会把蚂蚁往反方向弹

思路来源

乱搞AC

题解

L为左右端点距离,考虑时间每过2*L是一个循环,

这时候左端点会被撞n次,右端点会被撞n次,所以左右端点可以先被撞min(a/n,b/n)个循环

后面的模拟即可,更新最后一次被撞的时间

以上是大多数人的写法,下面考虑我的乱搞

考虑二分(事实上500ms二分会T)a柱子是什么时候被撞烂的,b柱子是什么时候被撞烂的

在把a看成是先被撞烂的柱子时,所有撞到b的都会弹回来,

这样可以求得一个a被撞烂的时间,和一个b被撞烂的时间,

二者较小的那个是真实被撞烂的时间,

因为较小的被撞烂的时候,较大的一定没被撞烂,

所以在此之前的蚂蚁对撞较小的都有贡献,另一个则不一定是,

因为后续蚂蚁可能会在较小端掉下去,并不会对撞较大端有“只数的贡献”

不妨较小被撞烂的是左端点,被撞烂的时间是t1,

较大被撞烂的是右端点,被撞烂的时间是t2,

考虑右-左被撞烂的时间差,

现在撞烂左端点的这根柱子的这只蚂蚁,记为蚂蚁A,

会在L秒之后到达较大的这根柱子,且L秒内朝着较小的这根柱子走的蚂蚁都会掉下去,

L秒内朝着较大这根柱子走的蚂蚁,都在A的前面,所以考虑A什么时候掉下去,

①如果t2<t1+L,说明有一只蚂蚁B把右端点撞烂了,并向左端点走,

A走到右端点的时候会掉下去,这在B走到左端点的前面,答案是t2+L

而且能在t2撞烂右端点,说明在t2-L(t2-L<t1)的时间到达了左端点,

这时候左端点并没有烂,所以没有蚂蚁掉下去,所以撞烂右端点的时间是真实时间

②如果t2>t1+L,说明右端点不可能被撞烂,因为t1撞烂左端点后,

A蚂蚁都没能撞烂右端点,而在A蚂蚁之前撞右端点的一定会在左端点掉下去,不能再撞了

这就说明A是最后一个从左端点掉下去的蚂蚁,答案是t1+2*L

③如果t2=t1+L,可以认为是A蚂蚁把右端点撞烂的,也可以认为右端点没烂,

这不重要,无论哪种情况A蚂蚁还要返回,答案仍是t1+2*L

然后发现这个东西可以不二分,直接用下标求

然后实践发现这个距离数组排序会T,

所以利用序列的几乎有序性,多扫几遍序列来排序

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const ll mx=1e9+1,all=2ll*mx;
int n,a[N],d[N],x,y,l[N],r[N];
ll lef,rig,lb,rb;
int main(){
	scanf("%d%lld%lld",&n,&lef,&rig);
	lef--;rig--;
	for(int i=0;i<n;++i){
		scanf("%d",&a[i]);
	}
	for(int i=0;i<n;++i){
		scanf("%d",&d[i]);
		if(d[i]==0)l[x++]=a[i];
	}
	for(int i=n-1;i>=0;--i){
		if(d[i]==1)l[x++]=2ll*mx-a[i],r[y++]=mx-a[i];
	}
	for(int i=0;i<n;++i){
		if(d[i]==0)r[y++]=a[i]+mx;
	}
	lb=l[lef%n]+1ll*(lef/n)*all;
	rb=r[rig%n]+1ll*(rig/n)*all;
	if(lb>rb)swap(lb,rb);
	if(rb>=lb+mx)printf("%lld\n",lb+all);
	else printf("%lld\n",rb+mx);
	return 0;
} 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值