A subsequence of a sequence is a sequence which is obtained by deleting zero or more elements from the sequence.
You are given a sequence A
in which every element is a pair of integers i.e A
= [(a1, w1), (a2, w2),..., (aN, wN)].
For a subseqence B
= [(b1, v1), (b2, v2), ...., (bM, vM)] of the given sequence :
- We call it increasing if for every i (1 <= i < M ) , bi < bi+1.
- Weight(B) = v1 + v2 + ... + vM.
Task:
Given a sequence, output the maximum weight formed by an increasing subsequence.
Input:
The first line of input contains a single integer T. T test-cases follow. The first line of each test-case contains an integer N. The next line contains a1, a2 ,... , aN separated by a single space. The next line contains w1, w2, ..., wN separated by a single space.
Output:
For each test-case output a single integer: The maximum weight of increasing subsequences of the given sequence.
Constraints:
1 <= T <= 5
1 <= N <= 150000
1 <= ai <= 109, where i ∈ [1..N]
1 <= wi <= 109, where i ∈ [1..N]
Sample Input:
2
4
1 2 3 4
10 20 30 40
8
1 2 3 4 1 2 3 4
10 20 30 40 15 15 15 50
Sample Output:
100
110
Explanation:
In the first sequence, the maximum size increasing subsequence is 4, and there's only one of them. We choose B = [(1, 10), (2, 20), (3, 30), (4, 40)]
, and we have Weight(B) = 100
.
In the second sequence, the maximum size increasing subsequence is still 4, but there are now 5 possible subsequences:
1 2 3 4
10 20 30 40
1 2 3 4
10 20 30 50
1 2 3 4
10 20 15 50
1 2 3 4
10 15 15 50
1 2 3 4
15 15 15 50
Of those, the one with the greatest weight is B = [(1, 10), (2, 20), (3, 30), (4, 50)]
, with Weight(B) = 110
.
Please note that this is not the maximum weight generated from picking the highest value element of each index. That value, 115, comes from [(1, 15), (2, 20), (3, 30), (4, 50)], which is not a valid subsequence because it cannot be created by only deleting elements in the original sequence.
题意:给定两个序列和 要求最大的第二个序列和 满足第一个序列满足递增。
解法:这题的背景应该是经典的最大上升子序列和。但考虑到那是一个O(n^2)算法。需要在这个的基础上进行优化。
解法1:维护一个单调set
有一件事可以确定,我们要是得大的数字的权值和尽可能大。这也是单调的意义所在。
如果一个数大但权值和小,我们可以不考虑这个数,因为有一个比它小的数可以添加构成更大的序列。
首先离散化,将所有的数字排序并离散化成由1开始递增的数列(用map)
用val[i]表示这个数字能构成的最大值。
然后每次插入时向后维护,移除那些不符合单调性的元素。
查找的时候进行二分。
但这样其实很慢,要1秒多。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <iomanip>
#include <cmath>
#include <climits>
#include <set>
#include <map>
#include <queue>
#define pii pair<int, int>
#define vi vector<int>
#define ll long long
#define eps 1e-3
using namespace std;
const int maxn = 2e5 + 10;
map<ll, ll> ind;
ll a[maxn];
ll w[maxn];
set<int> temp;
ll val[maxn];
int main()
{
//freopen("/Users/vector/Desktop/in", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
int n;
cin >> n;
temp.clear();
memset(val, 0, sizeof(val));
ind.clear();
for(int i = 0; i < n; i++)
{
cin >> a[i];
temp.insert(a[i]);
}
for(int i = 0; i < n; i++)
cin >> w[i];
int id = 1;
for(auto idx: temp)
ind[idx] = id++;
temp.clear();
for(int i = 0; i < n; i++)
{
int q = ind[a[i]];
/*for(auto idx = temp.rbegin(); idx != temp.rend(); idx++)
{
int elm = *idx;
//cout << elm << endl;
if(q > elm)
{
temp.insert(q);
val[q] = max(val[q], val[elm] + w[i]);
f = 1;
break;
}
}*/
set<int> :: iterator io = temp.lower_bound(q);
if(io == temp.begin())
{
temp.insert(q);
val[q] = max(val[q], w[i]);
}
else
{
io--;
int elm = *io;
temp.insert(q);
val[q] = max(val[q], val[elm] + w[i]);
}
set<int> :: iterator t = temp.find(q);
vector<int> del;
for(; t != temp.end(); t++)
{
if(val[*t] < val[q])
del.push_back(*t);
}
for(auto idx: del)
temp.erase(idx);
//cout << endl;
}
// for(auto t: temp)
// cout << t << ' ';
int ed = *temp.rbegin();
cout << val[ed] << endl;
}
return 0;
}
解法2:数状数组(bit)
用数状数组维护一段区间的最大值(记住了:数状数组也可以用于维护区间最大值)
读入,去重,每个数字从小到大对应为下标0、1、2.....
然后每次处理一个数,用lower_bound寻找大于等于它的第一个数,由于树状数组的下标从1开始,所以这里正好找的是前一个数
查询1-当前下标的最大值+w[i]
再更新即可。还是由于下标,要更新的是下一位。很巧妙了。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <iomanip>
#include <cmath>
#include <climits>
#include <set>
#include <map>
#include <queue>
#define pii pair<int, int>
#define vi vector<int>
#define ll long long
#define eps 1e-3
using namespace std;
const int maxn = 2e2 + 10;
map<int, int> ind;
int w[maxn];
int val[maxn];
ll bit[maxn];
int n;
void update(int x, ll v)
{
while(x < maxn)
{
bit[x] = max(bit[x], v);
x += x & -x;
}
}
ll query(int x)
{
ll res = 0;
while(x)
{
res = max(res, bit[x]);
x -= x & -x;
}
return res;
}
int main()
{
//freopen("/Users/vector/Desktop/in", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n;
vi a(n), b(n);
for(int i = 0; i < n; i++)
cin >> a[i];
b = a;
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());//将元素去重
// for(auto idx: b)
// cout << idx << ' ' ;
for(int i = 0; i < n; i++)
cin >> w[i];
ll ans = 0;
memset(bit, 0, sizeof(bit));
//bit的下标是从1开始的 正好对应的前一位
for(int i = 0; i < n; i++)
{
int pos = (int)(lower_bound(b.begin(), b.end(), a[i]) - b.begin());
ll temp = query(pos) + w[i];
ans = max(temp, ans);
update(pos + 1, temp);//更新当前位置的值 要记住bit的下标是从1开始的
}
cout << ans << endl;
}
return 0;
}
/*
2
4
1 2 3 4
10 20 30 40
8
1 2 3 4 1 2 3 4
10 20 30 40 15 15 15 50
*/