码迷,mamicode.com
首页 > 其他好文 > 详细

HDU-4719--Oh My Holy FFF(线段树优化DP)

时间:2020-07-05 13:24:34      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:不难   play   处理   优化   namespace   ble   str   时间   define   

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4719

题目大意:有n个人,第$i$个人的身高为$h_i$,现在要把这些人按照原来的顺序分为连续的若干段,要求每组的人数不超过$l$,同时,我们这每组的最后一个人身高为$b_i$,则有$b_i>b_{i-1}(b_0=0)$,现在我们设每种分组方案的价值为$\sum b_{i}^{2}-b_{i-1}$,问能够得到的最大价值是多少?

Sample Input

2
5 2
1 4 3 2 5
5 2
5 4 3 2 1

Sample Output

Case #1: 31
Case #2: No solution

实际上最朴素的DP不难想到,设dp[i]表示前i个人分成若干组的最大价值,那么则有$dp[i]=max_{j=[i-l,i-1]}{dp[j]+h_i^2-h_j}$

那么代码也就不难写出来了:

技术图片
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int mac=1e5+10;

int dp[mac],h[mac];

int main()
{
    int t,Case=0;
    scanf ("%d",&t);
    while (t--){
        int n,m;
        scanf ("%d%d",&n,&m);
        for (int i=1; i<=n; i++)
            scanf ("%d",&h[i]);
        memset(dp,0,sizeof dp);
        dp[1]=h[1]*h[1];
        for (int i=1; i<=n; i++){
            for (int j=max(1,i-m); j<i; j++){
                if (h[j]>=h[i]) continue;
                dp[i]=max(dp[i],dp[j]+h[i]*h[i]-h[j]);
            }
        }
        if (!dp[n]) {printf("Case #%d: No solution\n",++Case);}
        else {
            printf("Case #%d: %d\n",++Case,dp[n]);
        }
    }

    return 0;
}
View Code

只不过这样的话时间的复杂度会很高,就会导致T。。。

事实上将上面的式子变化一下就是:$dp[i]=h_i^2+max_{j=[i-l,i-1]}{dp[j]-h_j}$

而$max_{j=[i-l,i-1]}{dp[j]-h_j}$这个东西事实上可以用线段树来维护的,我们需要知道的是题目对顺序的要求,所以我们可以将他们的pos直接同步线段树的pos,那么这样一来查找的时候我们直接$query(1,n,1,pos[i]-l,pos[i]-1)$就可以了。那么怎么维护$b_i>b_{i-1}$呢,我们将其排序就好了,按照身高的升序排列,如果身高一样,则按照pos降序排列。因为后面的pos并不能影响前面的。

值得注意的是边界id的处理和爆int

以下是AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int mac=1e5+10;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lc rt<<1
#define rc rt<<1|1
typedef long long ll;

struct node
{
    int id,h;
    bool operator <(const node &a)const{
        if (h==a.h) return id>a.id;
        return h<a.h;
    }
}a[mac];

ll dp[mac];
ll tree[mac<<2];

void update(int l,int r,int rt,int pos,ll val)
{
    if (l==r){
        tree[rt]=val;
        return;
    }
    int mid=(l+r)>>1;
    if (mid>=pos) update(lson,pos,val);
    else  {update(rson,pos,val);}
    tree[rt]=max(tree[lc],tree[rc]);
}

ll query(int l,int r,int rt,int L,int R)
{
    ll ans=-1;
    if (l>=L && r<=R) return tree[rt];
    int mid=(l+r)>>1;
    if (mid>=L) ans=max(ans,query(lson,L,R));
    if (mid<R) ans=max(ans,query(rson,L,R));
    return ans;
}

int main()
{
    int t,Case=0;
    scanf ("%d",&t);
    while (t--){
        int n,m,mx=0;
        scanf ("%d%d",&n,&m);
        for (int i=1; i<=n; i++){
            int x;
            scanf ("%d",&x);
            a[i]=node{i+1,x};
        }
        sort(a+1,a+1+n);n++;
        memset(dp,0,sizeof dp);
        memset(tree,-1,sizeof tree);
        ll ans=-1;
        update(1,n,1,1,0);
        for (int i=1; i<=n; i++){
            ll p=query(1,n,1,max(1,a[i].id-m),a[i].id-1);
            if (p==-1) {
                if (a[i].id==n) break;
                continue;
            }
            dp[i]=1LL*a[i].h*a[i].h+p;
            if (a[i].id==n){
                ans=dp[i];
                break;
            } 
            update(1,n,1,a[i].id,dp[i]-a[i].h);
        }
        if (ans==-1) printf("Case #%d: No solution\n",++Case);
        else printf("Case #%d: %lld\n",++Case,ans);
    }

    return 0;
}

HDU-4719--Oh My Holy FFF(线段树优化DP)

标签:不难   play   处理   优化   namespace   ble   str   时间   define   

原文地址:https://www.cnblogs.com/lonely-wind-/p/13245743.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!