[HDU2829] Lawrence

[HDU2829] Lawrence

题意简析

定义一个序列的价值:序列中任意两个元素的积之和。

给定义一个长度为n的序列,可以从中间断开m次,求如何断开,使得产生的多段序列的价值和最小。

这种分段问题的单调性都比较明显

\(dp[i][j]\)表示当前分到第\(i\)个点,分了\(j\)段的方案

对于\(dp[i][j]\)的决策,\(j\)越大,决策点越大(分的段数越多,每段就越小)

对于每个\(i\)进行一次决策单调性分治求解,复杂度$n^2  log  n $

const int N=1010;
const ll INF=1ll<<50;
 
int n,m;
ll a[N],dp[N][N];
int s[N],qs[N];
 
void Solve(int p,int l,int r,int L,int R) {
    if(l>r) return;
    int mid=(l+r)>>1;
    ll mi=INF;
    int id=L;
    rep(i,L,R) {
        ll x=dp[i-1][mid-1]+1ll*(s[p]-s[i-1])*(s[p]-s[i-1])-(qs[p]-qs[i-1]);
        if(x<mi) mi=x,id=i;
    }
    dp[p][mid]=mi;
    Solve(p,l,mid-1,L,id);
    Solve(p,mid+1,r,id,R);
}
int main() {
    while(~scanf("%d %d",&n,&m) && n) {
        m++;
        rep(i,1,n) {
            a[i]=rd();
            s[i]=s[i-1]+a[i];
            qs[i]=qs[i-1]+a[i]*a[i];
        }
        memset(dp,63,sizeof dp);
        dp[0][0]=0;
        rep(i,1,n) Solve(i,1,min((int)i,m),1,i);
        printf("%lld\n",dp[n][m]/2);
    }
}

\[ \ \]

\[ \ \]

猜你喜欢

转载自www.cnblogs.com/chasedeath/p/11743234.html
hdu