LINK

设棍子总长度为 L L L

两只蚂蚁相遇,看作他们彼此穿过不改变方向(结果而已,等同于都改变方向)

那么每只蚂蚁不断向左撞击,然后向右撞击…

所以时间 2 L 2L 2L是一个循环,经过 2 L 2L 2L后所有蚂蚁撞左右分别一次且回到原位

所以前面的 min ⁡ ( a / n , b / n ) \min(a/n,b/n) min(a/n,b/n)个循环都是空循环,每次都是一样的(因为装不烂)

接下来一次,障碍物就可能被某只蚂蚁率先撞破了

可能是左可能是右,讨论起来非常麻烦,所以直接模拟

把蚂蚁分成向左的一类,向右的一类

直接考虑是向左的先走到边界还是向右的,每次移动一只蚂蚁来模拟

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
const int inf = 1e9+1;
int A,B,n,a[maxn],f[maxn];
int le[maxn],re[maxn],Le[maxn],Re[maxn];
long long solve()
{
	for(int i=1;i<=n;i++)
		if( f[i]==0 )	le[++le[0]] = a[i];//往左边走的蚂蚁存下来,坐标小到大 
	for(int i=n;i>=1;i--)
		if( f[i]==1 )	re[++re[0]] = a[i];//往右边走的蚂蚁存在来,坐标大到小 
	long long ans = 0;
	while( le[0]+re[0] )//只要还有蚂蚁没走出去 
	{
		int zuo = 1, you = 1, temp = 0;//temp表示最后一只蚂蚁撞墙需要的时间 
		while( zuo<=le[0] || you<=re[0] )//把本轮的每一只蚂蚁都走完,也就是模拟到最后一个蚂蚁撞墙 
		{
			/*
			考虑是左边的蚂蚁先撞到左边的障碍还是右边的蚂蚁先撞到右边的障碍 
			*/ 
			if( zuo<=le[0] && ( you>re[0] || le[zuo]<=inf-re[you] ) )//左边的蚂蚁先撞到障碍 
			{
				A--; //障碍物耐久减1 
				if( A>=0 )	Le[++Le[0]] = le[zuo];//储存一下这只蚂蚁,下一轮这个蚂蚁会因为撞墙往右边走 
				temp = le[zuo]; zuo++;//更新一下temp 
			}
			else if( you<=re[0] && ( zuo>le[0] || le[zuo]>inf-re[you] ) )
			{
				B--; 
				if( B>=0 )	Re[++Re[0]] = re[you];
				temp = inf-re[you]; you++;
			}
		}
		ans += temp; le[0] = re[0] = 0;//接下来,让所有的蚂蚁都移动temp个单位 
		for(int i=1;i<=Le[0];i++)	re[++re[0]] = temp-Le[i];//之前方向是左边的,撞墙后都会转向为右边 
		for(int i=1;i<=Re[0];i++)	le[++le[0]] = inf-( temp-(inf-Re[i]) );
		Le[0] = Re[0] = 0;
	}
	return ans;
}
int main()
{
	cin >> n >> A >> B;
	for(int i=1;i<=n;i++)	scanf("%d",&a[i] );
	for(int i=1;i<=n;i++)	scanf("%d",&f[i] );
	sort( a+1,a+1+n );
	int mi = min( A/n,B/n );
	/*经过2*(1e9+1)的时间后,每只蚂蚁都会撞左边的障碍一次,也会撞右边障碍一次,最后回到原来的位置 
	所以2*(1e9+1)是一个循环,经过一个循环障碍物耐久就降低n
	计算得到有mi个循环是空的,可以直接跳过,然后减去障碍物对应的耐久,加速这个过程 
	*/
	long long ans = 1ll*mi*2*inf;//mi个循环,每个循环耗时2*(1e9+1) 
	A -= mi*n, B -= mi*n;
	cout << ans+solve();
}