[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}$(其中$0\le x<k$)
(这个结论大概是挺难证的)
有了这个结论,首先枚举$x$,即确定了配对方案
接下来,先考虑暴力枚举$l_{1}$,之后将顺时针结果不超过$l_{1}$用顺时针做,再维护逆时针的最大值,通过将顺时针从小到大排序以及维护后缀逆时针最大值就可以做了
时间复杂度为$o(k^{2}\log k)$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",ans); 28 } 29 }