POJ 1769_Minimizing maximizer
题意:
一系列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之后位置不发生改变。
用
- 在第
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肯定要遍历一遍,就只能在最少次数的获取上优化了。不停的获取最少次数又不停的更新到
代码:
#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进行优化,可以降低计算的复杂度。