Educational DP Contest Q - Flowers(最长上升子序列+树状数组)
Q - Flowers
原题链接:https://atcoder.jp/contests/dp/tasks/dp_q
题目大意:
n支花,第i支花的高为w[i],价值为v[i],其中每支花的高度都不相同,范围在1到n。求从给定的花的序列中找到一段高度递增的子序列,求这段子序列的价值最大值。
解题思路:
建立数组$dp,dp[i]$为取第i朵花时的最大价值,在求要第i支花时的最大值时,要找到他前边比他矮的花的价值最大值,然后$dp[i]=dp[j]+v[i]$,在找$dp[j]$时,不能遍历。因为高度在$1-n$这个范围里,所以可以建立一个树状数组来存储前i个花的价值,这样就可以在$logn$的时间内求出前i支花中高度在$1-(w[i]-1)$的价值的最大值。
代码:
1 #include <bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 #define debug(a) cout<<#a<<":"<<a<<endl;
5 const ll INF=0x3f3f3f3f;
6 const ll N=1e6+7;
7 const ll mod=1e9+7;
8 ll maxn,minn;
9 ll T,n,m;
10 ll dp[N];
11 ll w[N];
12 ll v[N];
13
14 ll arr[N],ans[N]; //对应原数组和树状数组
15
16 ll lowbit(ll x){
17 return x&(-x);
18 }
19
20 void update(ll i,ll k){ //在i位置加上k
21 while(i<=n){
22 ans[i]=max(ans[i],k);
23 i=i+lowbit(i);
24 }
25 }
26
27 ll query(ll i){ //求arr[1 - i]的最大值
28 ll res = 0;
29 while(i>0){
30 res=max(res,ans[i]);
31 i =i-lowbit(i);
32 }
33 return res;
34 }
35
36 int main(){
37 cin>>n;
38 for(ll i=1;i<=n;i++){
39 scanf("%lld",w+i);
40 }
41 for(ll i=1;i<=n;i++){
42 scanf("%lld",v+i);
43 }
44 for(ll i=1;i<=n;i++){
45 dp[i]=v[i]+query(w[i]);
46 maxn=max(maxn,dp[i]);
47 update(w[i],dp[i]);
48 }
49 cout<<maxn<<endl;
50 return 0;
51 }