luogu2885

P2885 [USACO07NOV]电话线Telephone Wire

 

给出若干棵树的高度,你可以进行一种操作:把某棵树增高h,花费为h*h。

操作完成后连线,两棵树间花费为高度差*定值c。

求两种花费加和最小值。

输入输出样例

输入 #1
5 2
2
3
5
1
4
输出 #1
15

sol:显然暴力的dp很容易得到,dp[i][j]表示第i个高度为j个最小代价
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll S=0; char ch=' '; bool f=0;
    while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();}
    while(isdigit(ch)) {S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();}
    return (f)?(-S):(S);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0) {putchar('-'); x=-x;}
    if(x<10) {putchar(x+'0'); return;}
    write(x/10); putchar(x%10+'0');
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=100005,M=105,inf=0x3f3f3f3f;
int n,c,hig[N],mx,ans;
int dp[N][M];
inline int sqr(int x){return x*x;}
int main()
{
    freopen("luogu2885_data.in","r",stdin);
    int i,j,k;
    R(n); R(c);
    for(i=1;i<=n;i++)
    {
        R(hig[i]); mx=max(mx,hig[i]);
    }
    memset(dp,63,sizeof dp);
    dp[1][hig[1]]=0;
    for(i=1;i<=mx-hig[1];i++) dp[1][hig[1]+i]=i*i;
    for(i=2;i<=n;i++)
    {
        for(j=hig[i];j<=mx;j++) for(k=hig[i-1];k<=mx;k++)
        {
            dp[i][j]=min(dp[i][j],dp[i-1][k]+sqr(j-hig[i])+c*abs(j-k));
        }
    }
    ans=inf;
    for(i=hig[n];i<=mx;i++) ans=min(ans,dp[n][i]);
    Wl(ans);
    return 0;
}
View Code

然后发现容易拆开abs分类讨论一下即可

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0; bool f=0; char ch=' ';
    while(!isdigit(ch))    {f|=(ch=='-'); ch=getchar();}
    while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();}
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0) {putchar('-'); x=-x;}
    if(x<10) {putchar(x+'0'); return;}
    write(x/10); putchar((x%10)+'0');
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=100005,inf=0x3f3f3f3f;
int n,c,mx,hig[N];
int dp[N][105],mn[105];
inline int sqr(int x){return x*x;}
int main()
{
    freopen("luogu2885_data.in","r",stdin);
    int i,j;
    R(n); R(c);
    for(i=1;i<=n;i++) mx=max(mx,hig[i]=read());
    memset(dp,63,sizeof dp);
    for(i=hig[1];i<=mx;i++) dp[1][i]=sqr(i-hig[1]);
    for(i=2;i<=n;i++)
    {
        for(j=0;j<=hig[i-1]-1;j++) mn[j]=inf;
        for(j=hig[i-1];j<=mx;j++) mn[j]=min(mn[j-1],dp[i-1][j]-c*j);
        for(j=hig[i];j<=mx;j++) dp[i][j]=min(dp[i][j],mn[j]+sqr(j-hig[i])+c*j);
        mn[mx+1]=inf;
        for(j=mx;j>=hig[i-1];j--) mn[j]=min(mn[j+1],dp[i-1][j]+c*j);
        for(j=hig[i-1]-1;j>=1;j--) mn[j]=mn[hig[i-1]];
        for(j=hig[i];j<=mx;j++) dp[i][j]=min(dp[i][j],mn[j]+sqr(j-hig[i])-c*j);
//        for(j=hig[i];j<=mx;j++) cout<<i<<' '<<j<<' '<<dp[i][j]<<endl; putchar('\n');
    }
    int ans=inf;
    for(j=hig[n];j<=mx;j++) ans=min(ans,dp[n][j]);
    Wl(ans);
    return 0;
}
ac

 

 
posted @ 2019-07-29 22:16  yccdu  阅读(166)  评论(0编辑  收藏  举报