HDU 4719Oh My Holy FFF 线段树+DP

/*
**  日期: 2013-9-12
**  题目大意:有n个数,划分为多个部分,假设M份,每份不能多于L个。每个数有一个h[i],
**  每份最右边的那个数要大于前一份最右边的那个数。设每份最右边的数为b[i],
**  求最大的sum{b[i]² - b[i - 1]},1≤i≤M,其中b[0] = 0。
**  思路:朴素DP为,dp[i]表示以i为结尾的最大划分。那么dp[i] = max{dp[j] - h[j] + h[i]²},
**  1≤i-j≤L,h[j]<h[i]。这种会超时,采取线段树优化。因为有两个限制,考虑到若h[j]≥h[i],
**  那么求i的时候一定不会用到j,那么先按h排序再DP(h相同的,i大的排前面)。
**  __int64 没改完,导致wa了无数次
*/


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson rt<<1,left,m
#define rson rt<<1|1,m+1,right
#define mid  (left+right)>>1
using namespace std;

typedef __int64 LL ;
const int maxn = 100005;
LL maxt[maxn<<2];
int L,n;
struct node{
    int pos;LL h;
    node(int id = 0,LL hight = 0):pos(id),h(hight){}
    bool operator < (node a)const{
        if( h == a.h)return pos > a.pos;
        return h < a.h;
    }
}arr[maxn];
void update(int rt,int left,int right,int place,LL val){
    if( left == right){
        maxt[rt] = val;
        return ;
    }
    int m = mid;
    if( place <= m)update(lson,place,val);
    else update(rson,place,val);
    maxt[rt] = max(maxt[rt<<1],maxt[rt<<1|1]);
}
LL query(int rt,int left,int right,int l,int r){
    if( left >= l && right <= r){
        return maxt[rt];
    }
    int m = mid;
    LL res = -1;
    if( l <= m)res = max(res,query(lson,l,r));
    if( r > m )res = max(res,query(rson,l,r));
    return res;
}
LL solve(){
    sort(arr,arr+n);
    LL res = -1;
    memset(maxt,-1,sizeof(maxt));
    update(1,0,n,0,0);
    for(int i = 0; i < n; i++){
        LL tmp = query(1,0,n,max(arr[i].pos-L,0),arr[i].pos - 1);
        if( tmp == -1 ){
            if( arr[i].pos == n)return -1;
            continue;
        }
        res = tmp + (LL)arr[i].h*arr[i].h;
        if( arr[i].pos == n)return res;
        update(1,0,n,arr[i].pos,res - arr[i].h);
    }
    return res;
}
int main(){
    int t,cas = 1;LL h;
    scanf("%d",&t);
    while( t-- ){
        scanf("%d%d",&n,&L);
        for(int i = 0; i < n; i++){
            scanf("%I64d",&h);
            arr[i] = node(i+1,h);
        }
        LL ans = solve();
        printf("Case #%d: ",cas++);
        if( ans == -1)puts("No solution");
        else printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LUO257316/p/3317012.html