xmu网宿科技杯 厦门大学第四届程序设计积分赛 第四场 A题

//题目:A.连续数列
//题目链接:http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1465
//题意:将含有n个整数的数列A中的所有整数重新从小到大排序以后得到的新的数列B;
//      满足, 对于任意正整数i, j(1 <= i, j <= n), 恒有Bj - Bi = j - i 
//      求出变为连续数列所需花费的最小代价和。
//解题思路:因为只有一个最小的值所以可以把这个问题看成一个凹型的单峰图像  
//          从而利用三分法缩小区间,

      
#include<cstdio>
#include<vector>
#include<set>
#include<algorithm>
#define N 1000000000
#define LL long long
using namespace std;

int n;
LL num[10000+100];
LL l , r ;
LL calc (LL x)  //计算代价需要转化一下
{
  LL sum = 0;
  for(int i = 0; i < n; i++)
    sum = sum + abs(num[i] - i + x); //这里将num[i] - i,就是将该问题转化为将所有数字变为相同的数的最小代价
  return sum;
}

void slove()    //三分法
{
   l = -N, r = N;
   LL mid1, mid2;
  while(r - l > 2)   
  {
     mid1 = l +(r - l) / 3;          
         mid2 = l +(r - l) * 2 / 3;
         if (calc(mid1) > calc(mid2)) 
       l = mid1;
         else
       r = mid2;
  }
}

int main (void)
{
  int i ;
  scanf("%d", &n);
  
  for(i = 0; i < n; i++)
    scanf("%lld", &num[i]);

  sort(num, num+n);  
 
    slove();
    LL ans;
    LL min = 1000000000000000000LL;//没有加LL时 CE了一次
    for (i = l; i <= r; i++)   //这里注意不要只比较calc(l)和calc(r)
    {
        ans = calc(i);
      if(ans < min) min = ans;
  }
    
  printf("%lld\n", min);
  return 0;
}


你可能感兴趣的:(xmu网宿科技杯 厦门大学第四届程序设计积分赛 第四场 A题)