我是靠谱客的博主 害羞雪碧,这篇文章主要介绍计蒜客 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的全部内容,更多相关计蒜客内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复