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之后位置不发生改变。

dp[j]表示最大值到达j位置所需的最少sorter个数,有两种情况:

  • 在第i1个sorter中最大值k,满足ai1k<bi1,那么在第i个sorter中最大值则被移动到bi1的位置。
  • 否则,最大值位置不发生改变,则可以省去第i1个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进行优化,可以降低计算的复杂度。

posted @ 2016-02-17 14:44  zhuyujiang  阅读(120)  评论(0编辑  收藏  举报