The 2021 ICPC Asia East Continent Final Contest M 个人题解

link

答案具有单调性,考虑二分答案,设当且要验证的答案是 \(T\)

先考虑最优情况下怎么安排蚂蚁进洞和出洞。我们从 \(\frac{T}{2}\) 截成两部分。

第一个观察是对称性,即可以把每个蚂蚁的进洞和出洞时刻翻转。

考虑只有一个洞的特例,我们发现是先让所有蚂蚁出洞,再进洞,这已经是其中一个最优方案。这启发我们尝试证明存在时间截断点 \(\frac{T}{2}\),使得前一半进洞和后一半出洞。

先假设只有一只蚂蚁不符合这个安排,因为前一半里面少了两个向后半的匹配,所以这只蚂蚁一定可以等待到超过 \(\frac{T}{2}\) 而不超过 \(T\) 时刻进那个洞。

再假设有 \(k\) 只不符合,这时上下会各产生 \(k\) 个空缺,我们一定存在方案让一只蚂蚁等待或者提前出洞,归纳到子问题。

有了这个限制,问题变为了二分图最大匹配,左右部的点都形成了若干区间。

如果 \(T\) 是偶数,上述判定方法是没有问题的。否则会在中间时刻产生问题,因为此时可以同时存在进洞和出洞。

我们可以证明,在中间时刻产生的进洞和出洞数量相等。同时因为洞就那么多,所以两者都不超过 \(\frac{n}{2}\)

这个证明我们可以假想把中间时刻拆解成一段连续的时刻,套用上面的证明。

于是我们可以设置为原图中每个点的流量为 2, 中间时刻的点流量为 1,做最大匹配即可。

朴素的实现复杂度为 \(O(n\log n\log V)\),观察发现是类似区间平移的过程,可以做到 \(O(n(\log n+\log V))\)

下面的代码是朴素实现。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double dou;
typedef pair<int,int> pii;
#define fi first
#define se second
#define mapa make_pair
typedef long double ld;
typedef unsigned long long ull;
#define ep emplace_back
template <typename T>inline void read(T &x){
	x=0;char c=getchar();bool f=0;
	for(;c<'0'||c>'9';c=getchar()) f|=(c=='-');
	for(;c>='0'&&c<='9';c=getchar())
	x=(x<<1)+(x<<3)+(c^48);
	x=(f?-x:x);
}
const int N=1e6+5;
int T, n; ll m;
ll a[N];
struct node{
	ll x; int tp, cnt;
	inline bool operator <(const node &t)const{
		return x<t.x;
	}
};
bool check(ll lim){
	ll h=lim/2;
	vector<node> vec;
	for(int i=1; i<=n; ++i){
		vec.push_back((node){a[i]+1, 0, 2});
		vec.push_back((node){a[i]+h+1, 0, -1});
		vec.push_back((node){a[i]+lim-h+1, 0, -1});
		vec.push_back((node){h-a[i], 1, 1});
		vec.push_back((node){lim-h-a[i], 1, 1});
		vec.push_back((node){lim-a[i], 1, -2});
	}
	sort(vec.begin(), vec.end());
	__int128 sum=0, lst=0, lsum=0, rsum=0;
	for(int i=0; i+1<(int)vec.size(); ++i){
		if(vec[i].tp==0){
			lsum+=vec[i].cnt;
		}
		else{
			rsum+=vec[i].cnt;
		}
		if(vec[i].x==vec[i+1].x) continue;
		if(lsum>=rsum){
			sum+=rsum*(vec[i+1].x-vec[i].x);
			lst+=(lsum-rsum)*(vec[i+1].x-vec[i].x);
		}
		else{
			lst+=lsum*(vec[i+1].x-vec[i].x);
			__int128 cur=min(rsum*(vec[i+1].x-vec[i].x), lst);
			sum+=cur; lst-=cur;
		}
		if(sum>=m) return true;
	}
	return false;
}
void solve(){
	read(n); read(m); m*=2;
	for(int i=1; i<=n; ++i) read(a[i]);
	ll L=1, R=1e15, mid, ret=0;
	while(L<=R){
		mid=(L+R)/2;
		if(check(mid)){
			ret=mid; R=mid-1;
		}
		else{
			L=mid+1;
		}
	}
	printf("%lld\n", ret);
}
int main(){
	// freopen("D:\\nya\\acm\\A\\test.in","r",stdin);
	// freopen("D:\\nya\\acm\\A\\test.out","w",stdout);
	read(T);
	while(T--){
		solve();
	}
	return 0;
}
posted @ 2025-08-30 21:58  Displace  阅读(6)  评论(0)    收藏  举报