zoukankan      html  css  js  c++  java
  • BZOJ 2244 拦截导弹

    BZOJ 2244 拦截导弹

    题源:现在没了 借luogu的用用:https://www.luogu.org/problem/P2487

    sol:

    是一个二维条件捆绑的dp,可以考虑cdq分治或者二维线段树去搞,二维线段树比较卡空间,但是更简单粗暴

    想想cdq分治咋做。

    第一个询问直接cdq分治处理,第二个询问貌似直接记转移数量好像不太行,因为相同的答案转移的时候可能是并行关系而不是前驱后继关系。

    一个点可能被打下来,当且仅当这个点在一个合法的答案序列里,现在出现了新问题,如何确定一个点一定在一个合法序列里。

    可以想到一个点在合法序列里,当且仅当正着做(LDS)和反着做(LIS)到这个点的时候的答案加起来-1是最后答案,假设(g_{i,0/1})表示到(i)这个点正/反做的方案数,明显这个点在的合法序列个数是(g_{i,0} imes g_{i,1})

    然后就是用动态开点线段树去查前缀最大值捆绑一个方案数

    注意cdq的顺序,同时正着cdq完了之后别忘了先对序列反着排一遍序保证第一维正确性

    减少码量的方法是打翻转标记和重载的时候分类讨论

    记得回收空间,这样不会有复杂度损失

    这里有个小细节,cdq分治处理点的贡献的时候,注意一个当前答案为1的点不能被答案0+1更新,如果更新的话方案数会记重复,如果这个点为0可以用之前的一个点去更新。

    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    const int N = 1e5+7;
    #define R register
    #define debug printf("GG
    ")
    typedef double LL;
    struct SEGT {
      int lc, rc;
      struct MAX {
        int val, x;
        LL k;
        //MAX(){}
        inline MAX(int a = 0, int b = 0, LL c = 0) {
          val = a, x = b, k = c;
        }
      } p;
    } t[N*25];
    int cnt = 1;
    SEGT I;
    void clear(int u) {
      if (!u) return;
      t[u].p = SEGT::MAX(0, 0, 0);
      clear(t[u].lc), clear(t[u].rc);
      t[u].lc = t[u].rc = 0;
      if(u == 1) cnt = 1;
    }
    inline void pushup(int u) {
      if (t[t[u].lc].p.x == t[t[u].rc].p.x) {
        t[u].p = SEGT::MAX(t[t[u].lc].p.val, t[t[u].rc].p.x, t[t[u].lc].p.k + t[t[u].rc].p.k);
      } else {
        if (t[t[u].lc].p.x < t[t[u].rc].p.x) 
          t[u].p = SEGT::MAX(t[t[u].rc].p.val, t[t[u].rc].p.x, t[t[u].rc].p.k);
        else t[u].p = SEGT::MAX(t[t[u].lc].p.val, t[t[u].lc].p.x, t[t[u].lc].p.k);
      }
    }
    void ins(int &u, int l, int r, int pos, int x, LL k) { // pos 最大值 方案数 
      if (!u) u = ++cnt;
      if (l == r) {
        if (t[u].p.x == x) t[u].p.k += k;
        else if (t[u].p.x < x) t[u].p = SEGT::MAX(pos, x, k);
        return;
      }
      int MID = (l + r) >> 1;
      if (pos <= MID) ins(t[u].lc, l, MID, pos, x, k);
      else ins(t[u].rc, MID + 1, r, pos, x, k);
      pushup(u);
    }
    inline SEGT query(int u, int l, int r, int sl, int sr) {
      if (!u) return t[u];
      if (sl == l && sr == r) return t[u];
      int MID = (l + r) >> 1;
      if (sr <= MID) return query(t[u].lc, l, MID, sl, sr);
      else if (sl > MID) return query(t[u].rc, MID + 1, r, sl, sr);
      else {
        SEGT LC = query(t[u].lc, l, MID, sl, MID), RC = query(t[u].rc, MID + 1, r, MID + 1, sr);
        if (LC.p.x == RC.p.x) {
          LC.p.k += RC.p.k;
          return LC;
        } else {
          if (LC.p.x >= RC.p.x) return LC;
          else return RC;
        }
      }
    }
    int n, m;
    struct Node {
      int ai, bi, ci, aci;
      int f[2];
      LL g[2]; // f 转移max g方案数 
    } p[N*2];
    bool flip = 0;
    inline int cmp1(Node a, Node b) {
      if (flip) {
        if (a.bi == b.bi) return a.ai > b.ai;
        return a.bi < b.bi;
      }
      if (a.bi == b.bi) return a.ai < b.ai;
      return a.bi > b.bi;
    }
    inline int cmp2(Node a, Node b) {
      if (flip) return a.ai > b.ai;
      return a.ai < b.ai;
    }
    int RT = 1;
    void cdq(int l, int r, int o) {
      //printf("%d %d
    ", l, r);
      if (l == r) {
        if (!p[l].f[o]) {
          //if (!o) printf("%dx", l);
          p[l].f[o] = p[l].g[o] = 1;
        }
        return;
      }
      int MID = (l + r) >> 1;
      std :: sort(p + l, p + MID + 1, cmp2);
      cdq(l, MID, o);
      std :: sort(p + l, p + MID + 1, cmp1);
      std :: sort(p + MID + 1, p + r + 1, cmp1);
      clear(1);
      int pl = l, pr = MID + 1, nx;
      while (pl <= MID && pr <= r) {
        if (flip) {
          if (p[pl].bi <= p[pr].bi) ins(RT, 1, m, p[pl].aci, p[pl].f[o], p[pl].g[o]), pl++;
          else {
            SEGT nx = query(1, 1, m, 1, p[pr].aci);
            if (!nx.p.x) nx.p.k = 1;
            if (p[pr].f[o] == nx.p.x + 1 && nx.p.x > 0) p[pr].g[o] += nx.p.k;
            else if (p[pr].f[o] < nx.p.x + 1) p[pr].f[o] = nx.p.x + 1, p[pr].g[o] = nx.p.k;
            pr++;
          }
        } else {
          if (p[pl].bi >= p[pr].bi) ins(RT, 1, m, p[pl].aci, p[pl].f[o], p[pl].g[o]), pl++;
          else {
            SEGT nx = query(1, 1, m, p[pr].aci, m);
            if (!nx.p.x) nx.p.k = 1;
            if (p[pr].f[o] == nx.p.x + 1 && nx.p.x > 0) p[pr].g[o] += nx.p.k;
            else if (p[pr].f[o] < nx.p.x + 1) p[pr].f[o] = nx.p.x + 1, p[pr].g[o] = nx.p.k;
            pr++;
          }
        }
      }
      while (pr <= r) {
        SEGT nx = flip > 0 ? query(RT, 1, m, 1, p[pr].aci) : query(RT, 1, m, p[pr].aci, m);
        if (!nx.p.x) nx.p.k = 1;
        if (p[pr].f[o] == nx.p.x + 1 && nx.p.x > 0) p[pr].g[o] += nx.p.k;
        else if (p[pr].f[o] < nx.p.x + 1) p[pr].f[o] = nx.p.x + 1, p[pr].g[o] = nx.p.k;
        pr++;
      } 
      std :: sort(p + MID + 1, p + r + 1, cmp2);
      cdq(MID + 1, r, o);
    }
    int tmp[N];
    void cerr() {
      printf("F's VAL : 
    ");
      for (R int i = 1; i <= n; i++)
        printf("%d %d
    ", p[i].g[0], p[i].g[1]);
    }
    int main() {
      scanf("%d", &n);
      for (R int i = 1; i <= n; i++)
        scanf("%d%d", &p[i].bi, &p[i].ci), p[i].ai = i, tmp[i] = p[i].ci;
      // lower_bound
      std :: sort(tmp + 1, tmp + n + 1);
      m = std :: unique(tmp + 1, tmp + n + 1) - (tmp + 1);
      for (R int i = 1; i <= n; i++)
        p[i].aci = std :: lower_bound(tmp + 1, tmp + m + 1, p[i].ci) - tmp;
      // cdq
      cdq(1, n, 0); flip = 1; clear(1); std :: sort(p + 1, p + n + 1, cmp2); cdq(1, n, 1);
      //
      int anx = 0;
      LL pmax = 0;
      std :: sort(p + 1, p + n + 1, cmp2);
      for (R int i = 1; i <= n; i++)
        if (p[i].f[0] > anx) anx = p[i].f[0], pmax = p[i].g[0];
        else if (p[i].f[0] == anx) pmax += p[i].g[0] * p[i].g[1];
      //cerr();
      printf("%lld
    ", anx);
      flip = 0, std :: sort(p + 1, p + n + 1, cmp2);
      for (R int i = 1; i <= n; i++) {
        if (p[i].f[0] + p[i].f[1] - 1 == anx)
          printf("%lf ", (1.0 * p[i].g[0] * p[i].g[1]) / (1.0 * pmax));
        else printf("0.00000 ");
      }
      
    }
    
  • 相关阅读:
    Nginx安装详细指南
    git 常用命令
    oracle server config
    CentOS6.5下安装oracle11gR2
    oracle query
    oracle function
    oracle note
    正则表达
    DOM&BOM的起源、方法、内容、应用
    sticky
  • 原文地址:https://www.cnblogs.com/cjc030205/p/11715082.html
Copyright © 2011-2022 走看看