hdu4719 线段树优化dp

hdu4719 Oh My Holy FFF

题意

有一个长度为(n(1leq nleq 100000))的数列(a),将这个数列划分成几个子序列,每个子序列的长度不超过(L(1leq Lleq n)),并且每个子序列的最后一个元素严格单调递增。对于一种划分数为(k)的方案,设每个子序列的最后一个元素是(b[i](1leq ileq k))(b[0]=0),则这个划分方案的得分为(sum (b[i]^2-b[i-1])),计算对于序列的合法划分所能得到的最大得分。

题解

(f[i])表示以第(i)个元素结尾所能得到的最大得分,则(f[i]=max(f[j]+a[i]^2-a[j])),其中(i-Lleq jleq i-1)并且(a[j]<a[i])
可以将(f[j]+a[i]^2-a[j])拆成((f[j]-a[j]))(a[i]^2)两部分,其中(a[i]^2)(i)本身决定,无法改变,((f[j]-a[j]))可以放进线段树查找,得到满足(i-Lleq jleq i-1)的最大值。
对于(a[j]<a[i])这个限制条件,可以通过更改计算顺序来实现。将(a[i])从小到大排序,逐个插入线段树中,这样线段树中的(a[j])全部小于当前计算的(a[i]),所以(a[i])一定是由比它小的(a[j])转移过来的。

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int maxn=100010;
int T,n,L;
LL tree[4*maxn],dp[maxn];

struct node{
    int id;
    LL x;
    bool operator < (const node& t)const{
        if(x!=t.x) return x<t.x;
        return id>t.id;
    }
}a[maxn];

void pushup(int o){
    tree[o]=max(tree[o<<1],tree[o<<1|1]);  
}

void build(int o,int l,int r){
    if(l==r){
        tree[o]=-1;
        return;
    }
    int mid=(l+r)>>1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
    pushup(o);
}

void change(int o,int l,int r,int pos,LL v){
    if(l==r){
        tree[o]=v;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) change(o<<1,l,mid,pos,v);
    else change(o<<1|1,mid+1,r,pos,v);
    pushup(o);
}

LL query(int o,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr) return tree[o];
    int mid=(l+r)>>1;
    LL ans=-1;
    if(ql<=mid) ans=max(ans,query(o<<1,l,mid,ql,qr));
    if(qr>mid) ans=max(ans,query(o<<1|1,mid+1,r,ql,qr));
    return ans;
}

int main(){
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d %d",&n,&L);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i].x);
            a[i].id=i;
        }
        build(1,0,n);
        change(1,0,n,0,0);
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++){
            dp[a[i].id]=-1;
            LL t=query(1,0,n,max(0,a[i].id-L),a[i].id-1);
            if(t==-1) continue;
            dp[a[i].id]=t+a[i].x*a[i].x;
            change(1,0,n,a[i].id,dp[a[i].id]-a[i].x);
        }
        printf("Case #%d: ",cas);
        if(dp[n]==-1) printf("No solution
");
        else printf("%lld
",dp[n]);
    }
}
原文地址:https://www.cnblogs.com/fxq1304/p/14586858.html