Three Investigators[hdu6642]

题意

一个长度为 $n$ 的序列,对于每个前缀,求最多 $5$ 个互不相交的不下降子序列的元素和的最大值。

$n\leq 10^5,a_i\in[1,10^9]$

题解

$5$ 这个东西很有用,最终的复杂度很可能就是跟 $2^5$ 之类的相关。

把 $a_i$ 拆成 $a_i$ 个 $a_i$,那么答案转变成统计元素数量的最大值。

发现这个东西就是杨氏图表前 $5$ 层的长度之和。

杨表的插入过程如下:

1,若当前层没有元素比 $x$ 大,则把 $x$ 插在末尾。

2,否则用比 $x$ 大的最小的数 $y$ 代替 $x$,然后将 $y$ 插入下一层中。

那么用 $\mbox{map}$ 处理杨表,每次插入 $a_i$ 个 $a_i$,每层最多会使 $2$ 个数字拆开,因此时间复杂度 $O(2^5n\log n)$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
#define ll long long
#define S 5
inline int read()
{
int x=0; char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x;
}
map<int,ll> a[S];
ll ans;
void add(int k,ll num,int u)
{
if(k>=S) return;
a[k][u]+=num; ans+=num;
for(map<int,ll>::iterator it;num;)
{
it=a[k].lower_bound(u+1);
if(it==a[k].end()) break;
ll d=min((*it).second,num);
num-=d; ans-=d;
add(k+1,d,(*it).first);
if((*it).second==d) a[k].erase(it); else a[k][(*it).first]-=d;
}
}
int main()
{
for(int T=read();T;T--,ans=0)
{
for(int i=0;i<S;i++) a[i].clear();
for(int i=read(),x,n=i;i;i--) x=read(),add(0,x,x),printf((i==1)?"%lld\n":"%lld ",ans);
}
return 0;
}