这个题,题意就是,给你一个有N个点等距的环,编号[0,N-1],然后有些点上有一个或多个硬币,要移动这个硬币,使得所有的硬币在环上等距地放置且每个点只能放一个硬币,一个移动方案的花费定义为,每个硬币的移动距离中,最长的那个移动距离。
嗯,首先贴一下别人的题解,我这种智障训练时肯定是想不到的
嗯,然后,我就只能来证明一下了(想了好久
我们先把这些硬币的位置升序排序嘛,这个肯定是首先的,假如排序后为,a1,a2,a3,,,am
然后我们先假设一种最终位置,0,n/m,2*n/m,,,,(n-1)*n/m,然后我们定义ai移动到对应位置的距离是ai-i*n/m,
然后我们可以得到他们每个的花费,假设为b1,b2,b3,,,bm,然后显然,这个方案的花费就是max{ abs(bi) },
那么其他方案呢,嗯,显然,我们其他方案就是,0+j,n/m+j,2*n/m+j,,,(n-1)*n/m+j,0<=j<n/m,
嗯其实就是我们可以将b1,b2,b3,,,bm全都加x或减x,x随便取值,那我们想要的是max{ abs(bi) }最小,怎么使它最小呢,
我们可以观察一下这个序列的最大值和最小值,假设为ap和aq,他们之间的差为dis,这个值肯定是不变的,
那么我们肯定就是通过使序列统一加减某数,使得这两个数的绝对值都尽可能小,ap和aq之间一共dis+1个点(包括他们两个),然后我们就让0点坐落在他们的中间那里就行
,然后答案就是(dis+1)/2了,,他们到中间点的距离,分奇偶看下发现,这个值就可以,我这种弱智终于明白了。。。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <string>
#include <set>
#include <map>
using namespace std;
#define ll long long
#define maxn 20005
int num[maxn];
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int T;
scanf("%d", &T);
for (int kase = 1; kase <= T; ++kase)
{
int N, M;
scanf("%d%d", &N, &M);
for (int i = 0; i < M; ++i)
{
scanf("%d", &num[i]);
}
int ans = 0;
int step = N / M;
sort(num, num + M);
int maxnum = 0, minnum = 99999999;
for (int i = 0, pos = 0; i < M; ++i, pos += step)
{
maxnum = max(maxnum, num[i] - pos);
minnum = min(minnum, num[i] - pos);
}
ans = (maxnum - minnum + 1) / 2;
printf("Case #%d: %d\n", kase, ans);
}
//system("pause");
//while (1);
return 0;
}