zoukankan      html  css  js  c++  java
  • [USACO07NOV]电话线Telephone Wire

    [USACO07NOV]电话线Telephone Wire

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    电信公司要更换某个城市的网线。新网线架设在原有的 N(2 <= N <= 100,000)根电线杆上, 第
    i 根电线杆的高度为 height_i 米(1 <= height_i <= 100)。 网线总是从一根电线杆的顶端被引到
    相邻的那根的顶端,如果这两根电线杆的高度不同,那么电信公司就必须为此支付 C*电线
    杆高度差(1 <= C <= 100)的费用。电线杆不能移动, 只能在相邻电线杆间按原有的顺序架设
    网线。加高某些电线杆能减少架设网线的总花费,但需要支付一定的费用,一根电线杆加高
    X 米的费用是 X^2。 请你计算一下,如何合理地进行这两种工作,使网线改造工程的最小费
    用。

    输入

    • Line 1: Two space-separated integers: N and C

    • Lines 2..N+1: Line i+1 contains a single integer: heighti

    输出

    • Line 1: The minimum total amount of money that it will cost Farmer John to attach the new telephone wire.

    样例输入

    5 2
    2
    3
    5
    1
    4

    样例输出

    15
    题解:
    f[i][j]表示第i个电线杆高度为j时所需要的最少的费用。
    然后很快就可以得出暴力代码,每次枚举上一个电线杆的高度就可以了。
    先付上暴力代码:(TLE到爆表)
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<stack>
     9 #include<ctime>
    10 #include<vector>
    11 using namespace std;
    12 long long n,m;
    13 long long a[100001],f[100001][101],mmax;
    14 int main()
    15 {
    16     long long i,j,k;
    17     scanf("%lld%lld",&n,&m);
    18     memset(f,127/3,sizeof(f));
    19     for(i=1;i<=n;i++)
    20     {
    21         scanf("%lld",&a[i]);
    22         mmax=max(mmax,a[i]);
    23     }
    24     for(i=a[1];i<=mmax;i++)
    25     {
    26         int s=i-a[1];
    27         f[1][i]=s*s;
    28     }
    29     for(i=1;i<=n;i++)
    30     {
    31         for(j=a[i-1];j<=mmax;j++)
    32         {
    33             for(k=a[i];k<=mmax;k++)
    34             {
    35                 int s=k-a[i];
    36                 f[i][k]=min(f[i][k],s*s+f[i-1][j]+m*abs(j-k));
    37             }
    38         }
    39     }
    40     long long ans=2000000000000000000;
    41     for(i=a[n];i<=mmax;i++)
    42     ans=min(ans,f[n][i]);
    43     cout<<ans;
    44     return 0;
    45 }

    显然是需要优化的,仔细想一想就可以看出,每次实际上只有两种情况:

    1.i-1的高度比i低。

    2.i-1的高度比i高。

    第一种情况下f[i][j]的结果为f[i-1][min]+abs(j-min)*k+(j-a[i])^2显然是有最小值的,所以只要记录min就可以直接算出f[i][j]的值。

    第二种情况下f[i][j]的结果为f[i-1][min]+abs(j-min)*k+(j-a[i])^2,但由于随着j的增加每次min的值都有可能会改变,所以需要用到一个单调队列来记录最小值。

    以下为AC代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<stack>
     9 #include<ctime>
    10 #include<vector>
    11 using namespace std;
    12 long long n,m;
    13 long long a[100001],f[100001][101],mmax;
    14 int main()
    15 {
    16     long long i,j,k;
    17     scanf("%lld%lld",&n,&m);
    18     memset(f,127,sizeof(f));
    19     for(i=1; i<=n; i++)
    20     {
    21         scanf("%lld",&a[i]);
    22         mmax=max(mmax,a[i]);
    23     }
    24     for(i=a[1]; i<=mmax; i++)
    25     {
    26         int s=i-a[1];
    27         f[1][i]=s*s;
    28     }
    29     for(i=2; i<=n; i++)
    30     {
    31         int p[101],head=1,tail=0,mmin=0;
    32         for(j=a[i-1];j<a[i];j++)
    33         {
    34             if(f[i-1][j]+abs(a[i]-j)*m<f[i-1][mmin]+abs(a[i]-mmin)*m||mmin==0)
    35             mmin=j;
    36         }
    37         int ssss=max(a[i],a[i-1]);
    38         p[++tail]=ssss;
    39         for(j=ssss+1;j<=mmax;j++)
    40         {
    41             while(f[i-1][j]+abs(j-a[i])*m<f[i-1][p[tail]]+abs(p[tail]-a[i])*m&&head<=tail)tail--;
    42             p[++tail]=j;
    43         }
    44         for(j=a[i];j<=mmax;j++)
    45         {
    46             f[i][j]=min(f[i][j],f[i-1][mmin]+abs(j-mmin)*m+(j-a[i])*(j-a[i]));
    47             f[i][j]=min(f[i][j],f[i-1][p[head]]+abs(j-p[head])*m+(j-a[i])*(j-a[i]));
    48             if(f[i-1][mmin]-abs(j-mmin)*m>f[i-1][j])mmin=j;
    49             if(p[head]==j)head++;
    50         }
    51     }
    52     long long ans=1e18;
    53     for(i=a[n]; i<=mmax; i++)
    54     ans=min(ans,f[n][i]);
    55     cout<<ans;
    56     return 0;
    57 }
  • 相关阅读:
    Quartus II中的Waring(转)
    gym102391J Parklife (2019-2020 XX Open Cup, Grand Prix of Korea) 启发式合并
    gym102900L Traveling in the Grid World (2020 ICPC Shanghai Site)
    gym102341C Cloyster (Radewoosh+mnbvmar Contest (supported by AIM Tech)) 二分
    codeforces1452E Two Editorials (Educational Codeforces Round 98)
    gym102798 Caesar Cipher (2020 China Collegiate Programming Contest, Weihai Site) 线段树
    gym102452 I Incoming Asteroids (2019-2020 ICPC Asia Hong Kong Regional Contest) 抽屉原理
    HDU6820 Tree (2020杭电多校第5场1007) 树形dp
    POJ 3680 Intervals
    Min25筛(引入)
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/6950405.html
Copyright © 2011-2022 走看看