o o o o o o o o o o o o o o o o o o /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F\ /F/ \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \
o o o | o o o o | o o o o o o | o o o o o /F\ /F\ /F\ | /F\ /F\ /F\ /F\ | /F\ /F\ /F\ /F\ /F\ /F\ | /F\ /F\ /F\ /F\ /F/ \ / \ / \ | / \ / \ / \ / \ | / \ / \ / \ / \ / \ / \ | / \ / \ / \ / \ / \
 , b0 = 0 and 1 <= k <= M, if there are M groups in total. Note that M can equal to 1.
, b0 = 0 and 1 <= k <= M, if there are M groups in total. Note that M can equal to 1.2 5 2 1 4 3 2 5 5 2 5 4 3 2 1
Case #1: 31 Case #2: No solution
题意:有n个数,划分为多个部分,假设M份,每份不能多于L个。每个数有一个h[i],每份最右边的那个数要大于前一份最右边的那个数。设每份最右 边的数为b[i],求最大的sum{b[i]2 - b[i - 1]},1≤i≤M,其中b[0] = 0。
题解:dp[i]表示前i个数能达到的最大值。dp[i]=max(dp[i],dp[j]+h[i]*h[i]-h[j]),i-L<=j<i.
线段树优化:先排个序,按h从小到大排,相等的pos大的在前,这是为了保证严格升序。
然后逐个插入,更新a[i].pos位置的单点值,再维护区间最大值,详细见代码。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#define lson l,mid,idx<<1
#define rson mid+1,r,idx<<1|1
#define lc idx<<1
#define rc idx<<1|1
#define N 100010
#define ll long long
using namespace std;
int n,m;
struct node {
    int pos;
    ll num;
} a[N];
ll tree[N<<2];
void build(int l,int r,int idx) {
    tree[idx]=-1;
    if(r==l)return;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int l,int r,int idx,int x,ll k) {///把x位置的值更新
    if(l==r) {
        tree[idx]=max(tree[idx],k);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)update(lson,x,k);
    else      update(rson,x,k);
    tree[idx]=max(tree[lc],tree[rc]);
}
ll query(int l,int r,int idx,int x,int y) {
    if(l>=x&&y>=r) {
        return tree[idx];
    }
    int mid=(l+r)>>1;
    ll ans=-1;
    if(x<=mid)ans=max(ans,query(lson,x,y));
    if(y>mid) ans=max(ans,query(rson,x,y));
    return ans;
}
bool cmp(node a,node b) {
    if(a.num==b.num)return a.pos>b.pos;
    return a.num<b.num;
}
int main() {
    //freopen("test.in","r",stdin);
    int t;
    cin>>t;
    int ca=1;
    while(t--) {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) {
            scanf("%I64d",&a[i].num);
            a[i].pos=i+1;
        }
        sort(a+1,a+n+1,cmp);
        n++;
        build(1,n,1);
        update(1,n,1,1,0);
        ll ans=-1;
        for(int i=1; i<n; i++) {
            int l=(a[i].pos-m)>0?(a[i].pos-m):1,r=a[i].pos-1;///能一组的最左区间和最右区间-1
            ll it=query(1,n,1,l,r);
            if(it==-1&&a[i].pos==n) {///-1表示分不了组
                break;
            }
            if(it==-1) continue;
            it+=a[i].num*a[i].num;
            if(a[i].pos==n) {//已经更新到n了,直接跳出
                ans=it;
                break;
            }
            update(1,n,1,a[i].pos,it-a[i].num);//减去当前a[i].num,很巧妙
        }
        printf("Case #%d: ",ca++);
        if(ans==-1)printf("%s\n","No solution" );
        else         printf("%I64d\n",ans );
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu 4719 Oh My Holy FFF(dp线段树优化)
原文:http://blog.csdn.net/acm_baihuzi/article/details/47093453