UVALive

题目链接:https://vjudge.net/contest/241341#problem/I

题目大意:给你一个有N个点等距的环,编号[0,N-1],然后有些点上有一个或多个硬币,通过移动这些硬币使得所有的硬币在环上等距地放置且每个点只能放一个硬币,求每个硬币的移动距离中最长的那个移动距离的最小值。

解题思路:先对这m个硬币所在的初始位置排下序,然后我们可以随便假设它们等距要放的位置,比如0,n/m,1*n/m,……,(m-1)*n/m。然后依次计算这m个硬币移动到它们相应的位置所要移动的距离a1,a2,……,am,正的代表往前移动,负的代表往后移动。移动的最大距离当然就是他们的绝对值的最大值了。不过这不是唯一的方案,我们还可以调整要移动的终点位置,比如整体移动x个位置,终点位置 就变成了x,n/m+x,……,(m-1)*n/m+x,那我们怎么求移动距离最大值的最小值呢,哇这里说的有点蒙了,稍微理解理解。这里我们就要调整使a1,a2,a3,……am,使它们的最大值与最小值越接近0越好,比如a1,a2,a3,……am中的最大值为5,最小值为-2,表示往前移动的最多要移动5格,往后移动最多要移动2格,那我们可以给他们同时给整个序列都减去1,这样就变成最大值4和最小值-3了,所以结果为4,当他们最大值相差小于等于1时说明就不能移动了,而最大值与最小值之间相差最大值-最小值+1个点,我们需要尽量往0靠拢,所以除以2就是我们要求的结果了。看了这么就别人的题解,终于看懂了。。。

附上代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int inf=0x3f3f3f3f;
 7 typedef long long ll;
 8 int n,m,num[20005]; 
 9 
10 int main()
11 {
12     int t;
13     cin>>t;
14     int kase=1;
15     while(t--)
16     {
17         cin>>n>>m;
18         for(int i=0;i<m;i++) cin>>num[i];
19         sort(num,num+m);
20         int steps=n/m;
21         int maxx=-inf,minn=inf;
22         for(int i=0,j=0;i<m;i++,j+=steps)
23         {
24             maxx=max(maxx,num[i]-j);
25             minn=min(minn,num[i]-j);
26         }
27         printf("Case #%d: %d
",kase++,(maxx-minn+1)/2);
28     }
29     return 0;
30  } 
31  /*
32 3
33 12 4
34 11 1 2 5
35 15 5
36 1 9 1 1 2
37 10 2
38 3 4
39 */
原文地址:https://www.cnblogs.com/zjl192628928/p/9392029.html