我是靠谱客的博主 害羞雪碧,这篇文章主要介绍计蒜客 The Heaviest Non-decreasing Subsequence Problem dp LIS变形 || 线段树+dp,现在分享给大家,希望可以做个参考。

题目链接


题意:

每个数有一个val和weight,如果val < 0 weight 为 0 , val >= 1e4 weight 为5 ,其余为1.让你求一哥序列使得为weight最大并且val是不下降的.


思路:

我们知道在求普通的LIS的时候存的东西可能会被交换,换的时候会使得weight并不一定是最优解、

当时看大家过的那么多就写了一个坑爹的做法,把所有数离散一下用线段树维护了1 - id[i] 的最大值,维护一个最优解.

dp[i]表示LIS 第i个选上的最大值(即选出的这些使得weight最大的有第i个)。那么新加入的这个需要加在前面使得值最大的那个上.

(离散化之后下标对应值,所以一定是不下降的了。)

这个过程用线段树维护一下区间最大值即可.


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 3e5+5;
int a[maxn], v[maxn], val[maxn], Hash[maxn], id[maxn];
int dp[maxn], treeMax[maxn*4], Max;

void update(int root, int l, int r, int pos, int val)
{
    if(l == r)
    {
        treeMax[root] = max(treeMax[root], val);
        return ;
    }
    int mid = (l+r)/2;
    if(pos <= mid) update(root*2, l, mid, pos, val);
    else update(root*2+1, mid+1, r, pos, val);
    treeMax[root] = max(treeMax[root*2], treeMax[root*2+1]);
}

void query(int root, int l, int r, int i, int j)
{
    if(i <= l && j >= r)
    {
        Max = max(treeMax[root], Max);
        return ;
    }
    int mid = (l+r)/2;
    if(mid >= i) query(root*2, l, mid, i, j);
    if(mid < j) query(root*2+1, mid+1, r, i, j);
}

int main(void)
{
    int x, n = 1;
    while(~scanf("%d", &a[n]))
    {
        v[n] = a[n];
        if(a[n] >= 10000) v[n] -= 10000;
        if(a[n] >= 10000) val[n] = 5;
        else if(a[n] >= 0) val[n] = 1;
        else val[n] = 0;
        Hash[n] = v[n];
        n++;
    }
    n--;
    sort(Hash+1, Hash+1+n);
    int d = unique(Hash+1, Hash+1+n)-Hash-1;
    for(int i = 1; i <= n; i++)
        id[i] = lower_bound(Hash+1, Hash+1+d, v[i])-Hash;
    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        Max = 0;
        query(1, 1, n, 1, id[i]);
        dp[i] = Max+val[i];
        ans = max(ans, dp[i]);
        update(1, 1, n, id[i], dp[i]);
    }
    printf("%dn", ans);
    return 0;
}


其实这个题仔细想一下就是把价值为0的去掉,然后把价值为5的分成5个一样的放进去,然后求一次LIS,得到的LIS长度就是最大值了.


PS:如果价值不是5而是很大的数这个方法就不可以了.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=5e5+10;

int s[maxn]; 
int dp[maxn];
int main(){

	int len = 0;
	int x;
	while(~scanf("%d",&x))
	{
		if(x >= 0 && x < 10000)
		{
			s[len++] = x;
		}
		if(x >= 10000)
		{
			 x -= 10000;
			for(int i = 1;i <= 5;++i)
			s[len++] = x;
		}
	}
	//cout<<len<<endl;
		int ta = 0;  
        for(int i = 0;i < len;i++)  
        {  
            if(ta == 0 || s[i] >= dp[ta])  
            dp[++ta] = s[i];  
            else  
            {  
                int tmp = upper_bound(dp+1,dp+1+ta,s[i]) - dp;  
                dp[tmp] = min(dp[tmp],s[i]);  
            }  
        }  
        cout<<ta<<endl;
	return 0;
}



最后

以上就是害羞雪碧最近收集整理的关于计蒜客 The Heaviest Non-decreasing Subsequence Problem dp LIS变形 || 线段树+dp的全部内容,更多相关计蒜客内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(71)

评论列表共有 0 条评论

立即
投稿
返回
顶部