1. 程式人生 > 實用技巧 >2020ICPC上海 H-Rice Arrangement 貪心

2020ICPC上海 H-Rice Arrangement 貪心

2020ICPC上海 H-Rice Arrangement

題意

給定一個周長為\(n\)個單位的圓桌,有\(k\)個人圍著桌子坐,位置分別為\(a_1,a_2,\dots,a_k\),桌上有\(k\)碗手抓飯,位置分別為\(b_1,b_2,\dots,b_k\),服務員每次可以將桌子順時針或逆時針轉一個單位,當一個人面前剛好有一碗飯時,可以拿走這碗飯或等待下一個,問服務員最少轉多少單位能使每個人都能拿到一碗飯。

分析

\(a,b\)分別排序,列舉第一碗飯分配給哪個人,剩下的配對關係就確定了,求出兩個陣列\(x,y\),表示通過順時針轉動\(x[i]\)個單位或逆時針轉\(y[i]\)個單位,可以讓第\(i\)

個人拿到屬於他的飯,問題就轉化成了有\(k\)個有序對\((x_i,y_i)\),對於每個有序對,他要麼將\(x_i\)放入集合\(\mathit A\)中,要麼將\(y_i\)放入集合\(\mathit B\)中,問$ min(\text{max(A)2+max(B)},\text{max(A)+max(B)2})\(最小為多少,只需要將\)pair(x_i,y_i)\(排序,求\)min(x_i+max(y_{i+1;k})2,x_i2+max(y_{i+1;k}))$的最小值即可。

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e5+10;
const ll inf=1e18;
int T,n,k;
int a[2020],b[2020],c[2020],d[2020];
ll gao(){
	vector<pii>v;
	rep(i,0,k-1) v.pb(mp(c[i],d[i]));
	sort(v.begin(), v.end());
	ll ans=v[sz(v)-1].fi,mx=0;
	for(int i=sz(v)-1;i>=0;i--){
		mx=max(mx,(ll)v[i].se);
		if(i==0){
			ans=min(ans,mx);
		}else{
			ans=min(ans,v[i-1].fi+mx*2);
			ans=min(ans,v[i-1].fi*2+mx);
		}
	}
	return ans;
}
void solve(){
	cin>>n>>k;
	rep(i,0,k-1){
		cin>>a[i];
	}
	rep(i,0,k-1){
		cin>>b[i];
	}
	sort(a,a+k);
	sort(b,b+k);
	ll ans=inf;
	rep(i,0,k-1){
		rep(j,0,k-1) c[j]=(a[j]-b[(i+j)%k]+n)%n,d[j]=(b[(i+j)%k]-a[j]+n)%n;
		ans=min(ans,gao());
	}
	printf("%lld\n",ans);
}
int main(){
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}