AT4538 Flowers
题意
一个长度为 的序列,每个元素有两个权值 ,从这个序列中选出一个子序列,并满足以下要求:
-
单调递增。
-
在满足上一条的情况下,这个子序列的 之和最大。
分析
设 表示以 结尾的符合要求的子序列。
根据题意,则:
这样做是 的,显然过不了,不过题目中 比较小,所以我们从 入手。
其实,我们要找的 就是 之前所有高度在 之间的 中最大的一个。
这个显然可以用数据结构维护,我们需要一个支持单点修改,区间查询最大值的数据结构,树形结构比较麻烦,我们可以用分块来做。
本题只要维护一个前缀最大值,所以查询的区间中只有右边是散块,这样就很好写了,前面部分统计整块最大值,后面部分暴力统计。
单点修改更是简单,两行解决,把 所在的点和块更新即可。
代码
时间复杂度 。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int N=2e5+10,M=600;
int n;
ll dp[N],b[N],k[N],h[N],a[N],len,mx;
void change(int x,ll y){
b[x]=max(b[x],y);
k[x/len]=max(k[x/len],y);
}
ll ask(int x){
ll mx=0;
for(int i=0;i<x/len;i++)
mx=max(mx,k[i]);
for(int i=x/len*len;i<=x;i++)
mx=max(mx,b[i]);
return mx;
}
int main(){
n=read();
len=sqrt(n);
for(int i=1;i<=n;i++)
h[i]=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++){
dp[i]=ask(h[i]-1)+a[i];
change(h[i],dp[i]);
mx=max(mx,dp[i]);
}
cout<<mx;
return 0;
}

浙公网安备 33010602011771号