HDU 2829 Lawrence

$dp$,斜率优化。

设$dp[i][j]$表示前$i$个数字切了$j$次的最小代价。$dp[i][j]=dp[k][j-1]+p[k+1][i]$。观察状态转移方程,可以发现是一列一列推导出来的。可以初始化第一列,然后算第二列,然后算第三列。

暴力算的话时间复杂度是$O(n^3)$,需要优化。将$p[x][y]$换成带有$sum$的式子,一顿化简后,发现可以斜率优化。具体过程与HDU 3507差不多。不再赘述。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-10;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar();
    x = 0;
    while(!isdigit(c)) c = getchar();
    while(isdigit(c))
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
}

int n,m;
long long a[1005],sum[1005],p[1005][1005],dp[1005][1005];
int f1,f2,q[2000];

bool delete1(int x,int a,int b,int c)
{
    if(dp[b][x]-p[1][b]+sum[b]*sum[b]-dp[a][x]+p[1][a]-sum[a]*sum[a]<sum[c]*(sum[b]-sum[a])) return 1;
    return 0;
}

bool delete2(int x,int a,int b,int c)
{
    if((dp[c][x]-p[1][c]+sum[c]*sum[c]-dp[b][x]+p[1][b]-sum[b]*sum[b])*(sum[b]-sum[a])<
    (dp[b][x]-p[1][b]+sum[b]*sum[b]-dp[a][x]+p[1][a]-sum[a]*sum[a])*(sum[c]-sum[b])) return 1;
    return 0;
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break; m++;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int s=j,e=j+i-1;
                if(e>n) continue;
                if(i==1) { p[s][e]=0; continue; }
                p[s][e]=p[s+1][e]+a[s]*(sum[e]-sum[s]);
            }
        }

        for(int i=1;i<=n;i++) dp[i][1]=p[1][i];

        for(int j=2;j<=m;j++)
        {
            f1=0; f2=0; q[f2]=j-1;
            for(int i=j;i<=n;i++)
            {
                while(1)
                {
                    if(f2-f1+1<2) break;
                    if(delete1(j-1,q[f1],q[f1+1],i)) f1++;
                    else break;
                }

                dp[i][j] = dp[q[f1]][j-1]+p[q[f1]+1][i];

                while(1)
                {
                    if(f2-f1+1<2) break;
                    if(delete2(j-1,q[f2-1],q[f2],i)) f2--;
                    else break;
                }

                f2++; q[f2]=i;
            }
        }

        printf("%lld\n",dp[n][m]);
    }
    return 0;
}

 

posted @ 2017-01-25 11:14  Fighting_Heart  阅读(311)  评论(0编辑  收藏  举报