HDU2829

题目大意:给定一个长度为n的序列,至多将序列分成m+1段,每段序列都有权值,权值为序列内两个数两两相乘之和。m<=n<=1000.

分析:令w[i,j]表示区间[i,j]中两两乘积之和,f[i][j]表示前j个数分成i段的最小值。

f[i][j]=f[i-1][k]+w[k+1,j]

w[k+1,j]可以转换为w[1,j]-w[1,k]-sum[k]*(sum[j]-sum[k])

其中sum[j]表示前j个数的前缀和。

f[i][j]=f[i-1][k]+w[j]-w[k]-sum[k]*(sum[j]-sum[k])

令y=f[i-1][k]+w[j]-w[k]+sum[k]^2,x=sum[k],b=sum[j],g=f[i][j],则有:

y-bx=g

此为直线方程,b为定值,要求g最小,即为直线的截距最小。平面上有若干点(x,y),这些点是由各个决策点产生的。而将直线从下往上平移,它接触到的第一个点即为最佳决策点。因为斜率b是上升的,所以,下一阶段的直线方程斜率更高,于是最佳决策点一定形成了下凸包序列。

#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 1005
#define LL long long int
LL f[MAXN][MAXN],w[MAXN],sum[MAXN];
#define FZ(i,p) (f[i-1][p]-w[p]+sum[p]*sum[p])
int n,m,num[MAXN];
int que[MAXN],head,tail;
#define MAXZ (1LL<<22)
bool turnup(int i,int p1,int p2,int p3) //p1>p2>p3
{
    LL y1=FZ(i,p1);
    LL x1=sum[p1];
    LL y2=FZ(i,p2);
    LL x2=sum[p2];
    LL y3=FZ(i,p3);
    LL x3=sum[p3];
    if((x2-x3)*(y1-y2)>(x1-x2)*(y2-y3))return 1;
        else return 0;
}
int main()
{
    while(scanf("%d%d",&n,&m)&&(n||m))
    {
        memset(sum,0,sizeof sum);
        memset(w,0,sizeof w);
    m++;
    for(int i=1;i<=n;i++)
    {scanf("%d",&num[i]);
     sum[i]=sum[i-1]+num[i];
        w[i]=w[i-1]+sum[i-1]*num[i];
    }
    for(int i=1;i<=n;i++)
        f[1][i]=w[i];
    for(int i=2;i<=m;i++)
    {
        //f[i-1][i-1]=0;
        head=tail=1;
        que[tail++]=i-1;
        for(int j=i;j<=n;j++)
        {
            while(head<tail-1&&FZ(i,que[head+1])-FZ(i,que[head])<sum[j]*(sum[que[head+1]]-sum[que[head]]))head++;
            int k=que[head];
            f[i][j]=f[i-1][k]+w[j]-w[k]-sum[k]*(sum[j]-sum[k]);
            while(head<tail-1&&turnup(i,j,que[tail-1],que[tail-2])==0)
                tail--;
            que[tail++]=j;
        }
    }
    /*
    for(int i=1;i<=m;i++)
    {for(int j=1;j<=n;j++)
            printf("%I64d ",f[i][j]);
        printf("\n");
    }
    */
    printf("%I64d\n",f[m][n]);
}
}
时间: 2024-09-22 05:34:49

HDU2829的相关文章

HDU2829 Lawrence(斜率优化dp)

学了模板题之后上网搜下斜率优化dp的题目,然后就看到这道题,知道是斜率dp之后有思路就可以自己做不出来,要是不事先知道的话那就说不定了. 题意:给你n个数,一开始n个数相邻的数之间是被东西连着的,对于连着的一片的数,它们的价值就是两两乘积的和.所以4 5 1 2一开始就是4*5+4*1+4*2+5*1+5*2+1*2... 注意到两两乘积的和其实是可以这么算的((a1+a2+a3+..an)^2-(a1^2+a2^2+....))/2.现在我可以在数与数之间切m刀,问切完之后的最小价值是多少.

hdu2829之二维斜率优化DP

T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in the Arabian theater and led a group of Arab nationals in guerilla strikes against the Ottoman Empire. His primary targets were the railroads. A highl

HDU-2829 Lawrence (DP+四边形不等式优化)

题目大意:有n个敌方军火库呈直线排列,每个军火库有一个值vi,并且任意相邻的两个库之间都有通道相连.对于任意一条连起来的军火库链,它对我方的威胁可以用函数w(i,j)表示为:w(i,j)=vi*sum(i+1,j)+w(i+1,j)   i<j; w(i,j)=0               i=j; 现在,你有m个炸弹,每颗可以炸掉相邻的两个库之间的通道,求最终的总的最小威胁值. 题目分析:定义状态dp(i,j)表示用 i 颗炸弹使前 j 个库房脱离链条后前 j 个库房产生的最小威胁值,则状态

[HDU2829] Lawrence [四边形不等式优化dp]

题面: 传送门 思路: 依然是一道很明显的区间dp 我们设$dp\left[i\right]\left[j\right]$表示前$j$个节点分成了$i$块的最小花费,$w\left[i\right]\left[j\right]$表示把闭区间$\left[i,j\right]$放在一起产生的价值 那么转移就比较明显了: $dp\left[i\right]\left[j\right]=min\left(dp\left[i-1\right]\left[k-1\right]+w\left[k\right

DP总结 ——QPH

常见优化 单调队列 形式 dp[i]=min{f(k)} dp[i]=max{f(k)} 要求 f(k)是关于k的函数 k的范围和i有关 转移方法 维护一个单调递增(减)的队列,可以在两头弹出元素,一头压入元素. 队列中维护的是两个值.一个是位置,这和k的范围有关系,另外一个是f(k)的值,这个用来维护单调性,当然如果f(k)的值可以利用dp值在O(1)的时间内计算出来的话队列中可以只维护一个表示位置的变量. 枚举到一个i的时候,首先判断队首元素的位置是否已经不满足k的范围了,如果不满足就将队首