用单调队列优化的题目 我要长高

来源:互联网 发布:公众账号管理平台源码 编辑:程序博客网 时间:2024/04/27 19:39

我要长高

 http://www.acm.uestc.edu.cn/problem.php?pid=1685

Description

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

Input

有若干组数据,一直处理到文件结束。 每组数据第一行为两个整数:韩子数量N(1<=N<=50000)和舟子系数C(1<=C<=100) 接下来N行分别是韩i的高度(1<=hi<=100)。

 

首先建立方程,很容易想到的是,dp[i][j]表示第 i 个儿子身高为 j 的最低花费。分析题目很容易知道,当前儿子的身高花费只由前一个儿子影响。因此,

dp[i][j]=min(dp[i-1][k] + abs(j-k)*C + (x[i]-j)*(x[i]-j));其中x[i]是第i个儿子原本的身高

我们分析一下复杂度。

首先有N个儿子,这需要一个循环。再者,每个儿子有0到100的身高,这也需要一维。再再者,0到100的每一个身高都可以有前一位儿子的身高0到100递推而来。

所以朴素算法的时间复杂度是O(n^3)。题目只给两秒,难以接受!

分析方程:

当第 i 个儿子的身高比第 i-1 个儿子的身高要高时,

dp[i][j]=min(dp[i-1][k] + j*C-k*C + X);   ( k<=j ) 其中 X=(x[i]-j)*(x[i]-j)。

当第 i 个儿子的身高比第 i-1 个儿子的身高要矮时,

dp[i][j]=min(dp[i-1][k] - j*C+k*C + X);   ( k>=j )

对第一个个方程,我们令 f[i-1][k]=dp[i-1][k]-k*C,  g[i][j]=j*C+X; 于是 dp[i][j] = min (f[i-1][k])+ g[i][j]。转化成这样的形式,我们就可以用单调队列进行优化了。

第二个方程同理。

接下来便是如何实现,实现起来有点技巧。具体见下

代码:

#include<iostream>#include<cstdio>#define INF 0xfffffff#define min(a,b) a<b?a:busing namespace std;int q[101],dp[2][101];int main(){    int n,c,x,nowf,head,tail,cur;    while(scanf("%d%d",&n,&c)!=EOF)    {        cur=0;//高度最大为100        //以第一个人的身高初始化        scanf("%d",&x);        for(int i=0; i<x; i++)        {            dp[cur][i]=INF;//标记不可能状态        }        for(int i=x; i<=100; i++)        {            dp[cur][i]=(i-x)*(i-x);        }        for(int i=1; i<n; i++)        {            scanf("%d",&x);            cur=1-cur;//现在cur指向后一个人            head=tail=0;            for(int j=0; j<=100; j++) //比前一个人高,前面已经存了0~j-1            {                nowf=dp[1-cur][j]-c*j;                while(head<tail&&nowf<q[tail-1])                {                    tail--;                }                q[tail++]=nowf;                if(j<x)                {                    dp[cur][j]=INF;                }                else                {                    dp[cur][j]=q[head]+c*j+(x-j)*(x-j);                }            }            head=tail=0;            for(int j=100; j>=0; j--) //比前一个人矮,前面存了j+1~100            {                nowf=dp[1-cur][j]+c*j;                while(head<tail&&nowf<q[tail-1])                {                    tail--;                }                q[tail++]=nowf;                if(j>=x)                {                    dp[cur][j]=min(dp[cur][j],q[head]-c*j+(x-j)*(x-j));                }            }        }        int ans=INF;        for(int i=0; i<=100; i++)        {            ans=min(ans,dp[cur][i]);        }        printf("%d\n",ans);    }    return 0;}


具体请参考网址:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html


原创粉丝点击