Problem: http://www.acm.uestc.edu.cn/problem.php?pid=1644
最终结果可由通过组合数和最初始的排列表示出来,类似一个二项展开的样子,但是这样并不容易看出来最佳调整策略是怎样的。
于是在N比较小的时候,对random_shuffle了一万次,把最优的排列方案给输出了,但都是不唯一的:
3:2 1 3
4:3 1 4 2
5:3 2 5 4 1
6:4 2 6 1 5 3
7:5 3 6 1 7 2 4
8:5 3 7 1 8 2 6 4
9:6 4 8 1 9 2 7 3 5
从中间向两头看,就能发现规律了
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
int T, n;
ll a[60], b[60];
int main()
{
scanf("%d", &T);
for(int ca=0; ca<T; ++ca)
{
scanf("%d", &n);
for(int i=0; i<n; ++i)
scanf("%lld", a+i);
if(n == 1)
{
printf("Case #%d: %lld\n", ca+1, a[0]);
continue;
}
else if(n == 2)
{
printf("Case #%d: %lld\n", ca+1, abs(a[0]-a[1]));
continue;
}
sort(a, a+n);
if(n % 2)
{
int ind = n/2;
if((n/2) % 2)
{
for(int i=0; i<(n-1)/2; ++i)
{
b[ind] = a[i];
if(i % 2) ind -= 2*(i+1);
else ind += 2*(i+1);
}
ind = n/2+1;
for(int i=0; i<(n+1)/2; ++i)
{
b[ind] = a[n-1-i];
if(i % 2) ind += 2*(i+1);
else ind -= 2*(i+1);
}
}
else
{
for(int i=0; i<(n+1)/2; ++i)
{
b[ind] = a[n-1-i];
if(i % 2) ind -= 2*(i+1);
else ind += 2*(i+1);
}
ind = n/2+1;
for(int i=0; i<n/2; ++i)
{
b[ind] = a[i];
if(i % 2) ind += 2*(i+1);
else ind -= 2*(i+1);
}
}
}
else
{
int ind = n/2;
for(int i=0; i<n/2; ++i)
{
b[ind] = a[i];
if(i % 2) ind += 2*(i+1);
else ind -= 2*(i+1);
}
ind = n/2-1;
for(int i=0; i<n/2; ++i)
{
b[ind] = a[n-1-i];
if(i % 2) ind -= 2*(i+1);
else ind += 2*(i+1);
}
}
for(int j=0; j<n-1; ++j)
{
for(int k=0; k<n-1-j; ++k)
b[k] = b[k]-b[k+1];
}
printf("Case #%d: %lld\n", ca+1, abs(b[0]));
}
return 0;
}