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
*/