hdu4719 线段树优化dp

hdu4719 Oh My Holy FFF

题意

有一个长度为\(n(1\leq n\leq 100000)\)的数列\(a\),将这个数列划分成几个子序列,每个子序列的长度不超过\(L(1\leq L\leq n)\),并且每个子序列的最后一个元素严格单调递增。对于一种划分数为\(k\)的方案,设每个子序列的最后一个元素是\(b[i](1\leq i\leq 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-L\leq j\leq 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-L\leq j\leq 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\n");
        else printf("%lld\n",dp[n]);
    }
}
posted @ 2021-03-27 20:29  fxq1304  阅读(31)  评论(0编辑  收藏  举报