[测试博客题解]二分模板(导弹拦截)

[洛谷NOIP1999 普及组] 导弹拦截(DP+二分维护单调不上升和单调下降子序列)

  1. 首先用二分不断替换or添加 维护一个不上升子序列
  2. 第二个维护的是每次新系统的子序列末尾的min值的一个数组
    int main()
    {
        int x;
        while (cin >> x)
            a[++n] = x;
        int len = 1;
        f[len] = a[1];
        for (int i = 2; i <= n; i++)
        {
            int l = 0, r = len + 1;
            while (l + 1 != r) // 找小于a[i]的第一个数
            {
                int mid = (l + r) / 2;
                if (f[mid] >= a[i])//因为这里维护的是最长不上升子序列
                    l = mid;//因此这里的l和r应该反着取
                else
                    r = mid;
                            //左侧l都是>=a[i],r相反,如果r没变,说明a[len+1]=a[i];
                            //这时候发现规定的r没变,并且r=len+1(模板的优越性),否则替换末尾值
            }
            f[r] = a[i];
            if(r == len + 1) len++;
        }
        cout << len << endl;
        int cnt = 1;
        g[cnt] = a[1];//g[i]记录的是每次子序列末尾的最小值,但是当我们发现g[mid]>=a[i],
                      //则可以有更优越的a[i]替换末尾
        for (int i = 2; i <= n; i++)
        {
            int l = 0, r = cnt + 1;
            while (l + 1 != r)
            {
                int mid = (l + r) / 2;
                if (g[mid] < a[i])//如果都是<a[i]的值,那么就需要重开系统,这时候发现
                    l = mid;//居然发现r=cnt+1,那么默认g[r]=a[i]
                else
                    r = mid;
            }
            g[r] = a[i];
            if(r == cnt + 1) cnt ++;
        }
        cout << cnt << endl;
        return 0;
    }

     

posted @ 2023-04-17 17:40  Thecode_Wm  阅读(55)  评论(0)    收藏  举报