UESTC_我要长高 CDOJ 594

本博客探讨如何通过优化策略最小化韩家演艺损失,面对舟子的恶意言论,利用单调队列等算法技术解决实际问题,旨在提供一种减少损失的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

韩父有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;
}

 

转载于:https://www.cnblogs.com/Xiper/p/4467718.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值