[gym102900H]Rice Arrangement

(可以先阅读题目中关于顺逆时针的定义,避免理解错误)

考虑一盘菜$b_{i}$被$a_{j}$吃掉,对于其最后一次移动:如果是顺时针,则称$b_{i}$的移动区间为$[a_{j},b_{i}]$(若$b_{i}<a_{j}$则为$[a_{j},n)cup[0,b_{i}]$的环),反之类似(特别的,如果$a_{j}=b_{i}$则区间为$[b_{i},b_{i}]$)

记顺时针的最大移动区间为$l_{1}$,逆时针为$l_{2}$,答案即为$l_{1}+l_{2}+min(l_{1},l_{2})$

若某两个人移动区间相互包含,对两者移动方向分类讨论,可以发现都可以更换配对方式使得$l_{1}$和$l_{2}$不增加,换言之存在最优解使得任意两盘菜移动区间不包含

(注意:环的包含可以看作集合的包含)

通过这个,我们可以得到这样一个结论:将$a_{i}$和$b_{i}$从小到大排序后,存在一组最优解,满足存在$x$使得是$a_{i}$匹配$b_{(i-1+x)mod k+1}$(其中$0le x<k$)

(这个结论大概是挺难证的)

有了这个结论,首先枚举$x$,即确定了配对方案

接下来,先考虑暴力枚举$l_{1}$,之后将顺时针结果不超过$l_{1}$用顺时针做,再维护逆时针的最大值,通过将顺时针从小到大排序以及维护后缀逆时针最大值就可以做了

时间复杂度为$o(k^{2}log k)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1005
 4 pair<int,int>v[N];
 5 int t,n,m,ans,a[N],b[N],mx[N];
 6 int len(int x,int y){
 7     if (x<=y)return y-x;
 8     return m-(x-y);
 9 }
10 int main(){
11     scanf("%d",&t);
12     while (t--){
13         scanf("%d%d",&m,&n);
14         for(int i=0;i<n;i++)scanf("%d",&a[i]);
15         sort(a,a+n);
16         for(int i=0;i<n;i++)scanf("%d",&b[i]);
17         sort(b,b+n);
18         ans=m;
19         for(int i=0;i<n;i++){
20             for(int j=0;j<n;j++)v[j]=make_pair(len(a[j],b[(j+i)%n]),len(b[(j+i)%n],a[j]));
21             sort(v,v+n);
22             mx[n]=0;
23             for(int j=n-1;j>=0;j--)mx[j]=max(mx[j+1],v[j].second);
24             ans=min(ans,mx[0]);
25             for(int j=0;j<n;j++)ans=min(ans,v[j].first+mx[j+1]+min(v[j].first,mx[j+1]));
26         }
27         printf("%d
",ans);
28     }
29 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14360331.html