韩父有N个儿子,分别是韩一,韩二…韩N。由于韩家演技功底深厚,加上他们间的密切配合,演出获得了巨大成功,票房甚至高达2000万。舟子是名很有威望的公知,可是他表面上两袖清风实则内心阴暗,看到韩家红红火火,嫉妒心遂起,便发微薄调侃韩二们站成一列时身高参差不齐。由于舟子的影响力,随口一句便会造成韩家的巨大损失,具体亏损是这样计算的,韩一,韩二…韩N站成一排,损失即为C×(韩i与韩i+1的高度差(1i<N))之和,搞不好连女儿都赔了.韩父苦苦思索,决定给韩子们内增高(注意韩子们变矮是不科学的只能增高或什么也不做),增高1cm是很容易的,可是增高10cm花费就很大了,对任意韩i,增高Hcm的花费是H2.请你帮助韩父让韩家损失最小。

Input

有若干组数据,一直处理到文件结束。

每组数据第一行为两个整数:韩子数量N(1N50000)和舟子系数C(1C100)

接下来N行分别是韩i的高度(1hi100)。

Output

对每组测试数据用一行输出韩家的最小损失。

Sample input and output

Sample InputSample Output
5 2
2
3
5
1
4
15

 

解题报告

用单调队列来优化(正解)...空间复杂度也可以优化到O(100*2)...好吧我又没有优化

当时先用的线段树来O(log)得到最优解,结果本机测试跑极限数据1.5s+才出。。。果断放弃(常数太大)

之后采用rmq...交了一发TLE,彻底断了我的念头...

 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
typedef long long ll;
using namespace std;
const int maxn = 5e4 + 500;
int n,c,h[maxn];
ll  q[105];
ll  f[maxn][105];
ll  MAX;

int main(int argc,char *argv[])
{
  MAX = 1 << 25;
  MAX *= MAX;
  while(scanf("%d%d",&n,&c) != EOF)
   {
         for(int i = 1 ; i <= n ; ++ i)
          scanf("%d",h+i);
         for(int i = 1 ; i <= n ; ++ i)
          for(int j = 1 ; j <= 100 ; ++ j)
           f[i][j] = MAX;
         for(int i = h[1] ; i <= 100 ; ++ i)
           f[1][i] = (i-h[1])*(i-h[1]);
         int front , rear ;
         for(int i = 2 ; i <= n ; ++ i)
          {
                front = rear = 0;
                for(int j = h[i-1] ; j <= 100 ; ++ j)
                 {
                       while(front < rear && f[i-1][q[rear-1]]-c*q[rear-1] > f[i-1][j]-c*j)
                          rear--;
                       q[rear++] = j;
           }
          for(int j = h[i] ; j <= 100 ; ++ j)
            if (j >= q[front])
                 f[i][j] = f[i-1][q[front]] - c*q[front] + c*j + (j-h[i])*(j-h[i]);
          front = rear = 0;
          for(int j = h[i-1] ; j <= 100 ; ++ j)
           {
                 while(front < rear && f[i-1][q[rear-1]]+c*q[rear-1] > f[i-1][j]+c*j )
                  rear--;
                 q[rear++] = j;
           }
          for(int j = h[i] ; j <= 100 ; ++ j)
           {
                 while(j > q[front] && front < rear)
                  front++;
                 if (q[front] >= j) 
                  f[i][j] = min(f[i][j],f[i-1][q[front]] + c*q[front] - c*j + (j-h[i])*(j-h[i]));
           }
       }
      ll ans = f[n][h[n]];
      for(int j = h[n] ; j <= 100 ; ++ j)
       ans = min(ans,f[n][j]);
      printf("%lld\n",ans);
   }
  return 0;
}

 

posted on 2015-04-29 23:04  天心散人  阅读(390)  评论(0编辑  收藏  举报