题意:
一系列m个1~n区间,每个区间固定对某个子区间进行排序,顺序选择若干区间,使最终覆盖所有区间。
分析:
computes the length of the shortest subsequence of the initial sequence of sorters still producing correct results for all possible input data
要想明白几点:
- 输入时最大值的位置情况不确定,但是只要求出最大值在第一个位置的最短sorter序列,其他位置的情况就均满足了。
- 怎样删才能保证正常输出?就是最大值在删去中间几个sorter之后位置不发生改变。
用 dp[j] 表示最大值到达 j 位置所需的最少sorter个数,有两种情况:
- 在第
i−1 个sorter中最大值k,满足 ai−1≤k<bi−1 ,那么在第 i 个sorter中最大值则被移动到bi−1 的位置。- 否则,最大值位置不发生改变,则可以省去第 i−1 个sorter
可以得到状态转移方程:
dp[b[i]] = min(dp[b[i]], dp[j] + 1); a[i]<= j < b[i]
然后就TLE了。。。。然后就一脸懵逼.jpg
m个sorter肯定要遍历一遍,就只能在最少次数的获取上优化了。不停的获取最少次数又不停的更新到 dp[b[i]] ,单节点更新问题,可以用线段树优化,时间复杂度降为 O(mlogn) 。
代码:
#include<cstdio> #define min( a, c ) (a)<(c)?(a):(c) const int maxn = 500005, INF = 0x3fffffff; int a[maxn], b[maxn], m[3*maxn]; void build(int k, int l, int r) { m[k] = INF; if(l == r - 1) return; build(k * 2 + 1,l, (l+r)/2); build(k * 2 + 2, (l+r)/2, r); } void update(int a, int x, int k, int l, int r) { m[k] = min(x, m[k]); if(l < r-1){ int m = (l+r)/2; if(m > a) update(a, x, k * 2 + 1, l, m); else update(a, x, k * 2 + 2, m, r); } } int query(int a, int b, int k, int l, int r) { if(a >= r|| b <= l) return INF; else if(a <= l && r <= b) return m[k]; else { int ta = query(a, b, k * 2 + 1, l, (l+r)/2); int tb = query(a, b, k * 2 + 2, (l + r)/2, r); return min(ta, tb); } } int main (void) { int n, _m;scanf("%d%d",&n,&_m); build(0, 0, n); update(0, 0, 0, 0, n); for(int i = 0; i < _m; i++) { scanf("%d%d",&a[i],&b[i]); int t = query(a[i]-1, b[i], 0, 0, n) + 1; update(b[i]-1, t, 0, 0, n); } printf("%d\n",query(n-1, n, 0, 0, n)); }
选择合适的数据结构对dp进行优化,可以降低计算的复杂度。