2017CCPC 秦皇岛 A
有m个桌子组成的圆环,n个人坐在圆环里。(m>=n)
有q个A题信息,机器人负责给A题的人发气球,但是机器人只能顺时针走。
所有人们会有愤怒值,交题与获得气球的时间差为愤怒值,要求使得愤怒值之和最小。
考虑三点的圆环,发现其实所有的交题信息都可以转化为最多不同的三个状态。因为在一个环上从一点到另一点的距离只有n种可能,0..n-1。
推广到n个点,最多只有不同的n个状态。
我们把每个点的状态选一个代表点来研究问题。
比如三个点。(1,1)、(2,1)、(3,1)代表了所有的状态,任何其他的信息都与这三个之一等价,所以只用考虑这三个点。
先算出每个点从1出发的愤怒值。
当我们选中n个点其中一个点时,在这个点前面的点(愤怒值比它小的点)的愤怒值会增加m-angry[i]。从三个点可知愤怒值变化等同与距离变化。
同时在这个点后面的点(愤怒值比它大的点)愤怒值会减小angry[i]。
#include <bits/stdc++.h> #define pb push_back #define mp make_pair #define x first #define y second #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define up rt,rt<<1,rt<<1|1 #define mem(x) memset(x,0,sizeof(x)) #define mem1(x) memset(x,-1,sizeof(x)) #define LMissher using namespace std; typedef long long ll; typedef double db; const int M = 1e5+7; const double pi = acos(-1); const int inf = 2147483647; const int mod = 1e9+7; int _,n,a[M],m,p; ll tot[M]; int main(){ #ifdef LMissher freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif scanf("%d",&_); while(_--){ ll cnt=0;//从1号桌出发的愤怒值 scanf("%d%d%d",&n,&m,&p);//n people,m table ,p solved for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=p;i++){ ll team,time; scanf("%lld%lld",&team,&time); time%=m;if(time==0) time=m;//在交题的时间机器人走到哪个位置 if(time<=a[team]) tot[i]=a[team]-time;//机器人在交题者的"前面" else tot[i]=1ll*m-time+a[team];//机器人在交题者的"后面" cnt+=tot[i]; } sort(tot+1,tot+p+1);//总共的状态其实最多只有n种,分别为0...n-1,不过不去重不影响答案 ll ans=1e18; for(int i=1;i<=p;i++){ ans=min(ans,cnt+1ll*(i-1)*(1ll*m-tot[i])-1ll*(p-i+1)*tot[i]);//枚举从不同位置出发 } printf("%lld\n",ans); } return 0; }