ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-07-05 13:08:01  阅读:275  来源: 互联网

标签:Case HDU Holy Oh int max pos include dp


题目链接: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;
}

标签:Case,HDU,Holy,Oh,int,max,pos,include,dp
来源: https://www.cnblogs.com/lonely-wind-/p/13245743.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有