zoukankan      html  css  js  c++  java
  • UOJ Round #11

    A

    记忆化一下,直接爆搜即可。

    状态数非常少,分析出的上界大约是 (10^7) 左右,但实际上只有 (10^5) 的样子。

    #include <bits/stdc++.h>
    
    #define IL __inline__ __attribute__((always_inline))
    
    #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
    #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
    #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
    #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
    
    typedef long long LL;
    
    template <class T>
    IL bool chkmax(T &a, const T &b) {
      return a < b ? ((a = b), 1) : 0;
    }
    
    template <class T>
    IL bool chkmin(T &a, const T &b) {
      return a > b ? ((a = b), 1) : 0;
    }
    
    template <class T>
    IL T mymax(const T &a, const T &b) {
      return a > b ? a : b;
    }
    
    template <class T>
    IL T mymin(const T &a, const T &b) {
      return a < b ? a : b;
    }
    
    template <class T>
    IL T myabs(const T &a) {
      return a > 0 ? a : -a;
    }
    
    const int INF = 0X3F3F3F3F;
    const double EPS = 1E-8, PI = acos(-1.0);
    
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define OK DEBUG("Passing [%s] in LINE %d...
    ", __FUNCTION__, __LINE__)
    #define SZ(x) ((int)(x).size())
    
    namespace Math {
    const int MOD = 998244353;
    
    IL int add(int a, int b) {
      a += b;
      return a >= MOD ? a - MOD : a;
    }
    
    template <class ...Args>
    IL int add(int a, const Args &...args) {
      a += add(args...);
      return a >= MOD ? a - MOD : a;
    }
    
    IL int sub(int a, int b) {
      a -= b;
      return a < 0 ? a + MOD : a;
    }
    
    IL int mul(int a, int b) {
      return (LL)a * b % MOD;
    }
    
    template <class ...Args>
    IL int mul(int a, const Args &...args) {
      return (LL)a * mul(args...) % MOD;
    }
    
    IL int quickPow(int a, int p) {
      int ret = 1;
      for (; p; p >>= 1, a = mul(a, a)) {
        if (p & 1) {
          ret = mul(ret, a);
        }
      }
      return ret;
    }
    }
    
    using namespace Math;
    
    const int MAXN = 100 + 5;
    
    using Arr = std::array<int, 100>;
    using Node = std::pair<int, Arr>;
    
    Arr s, t;
    int n, m;
    std::map<Node, int> mp;
    
    int DFS(int c, const Arr &cur) {
      if (c >= m) {
        return cur == t;
      }
      Node now = Node(c, cur);
      auto it = mp.find(now);
      if (it != mp.end()) {
        return it->second;
      }
      Arr t = cur;
      int x = t[0], ans = cur == ::t;
      FOR(i, 0, 3) {
        if (x != i) {
          t[0] = i;
          ans = add(ans, DFS(c + 1, t));
          t[0] = x;
        }
      }
      FOR(i, 1, n) {
        int y = t[i];
        if (y != x) {
          FOR(j, 0, 3) {
            if (x != j && y != j) {
              t[i] = j;
              ans = add(ans, DFS(c + 1, t));
              t[i] = y;
            }
          }
          break;
        }
      }
      return mp[now] = ans;
    }
    
    int main() {
      scanf("%d%d", &n, &m);
      FOR(i, 0, n) {
        int x;
        scanf("%d", &x);
        -- x;
        s[i] = x;
      }
      FOR(i, 0, n) {
        int x;
        scanf("%d", &x);
        -- x;
        t[i] = x;
      }
      printf("%d
    ", DFS(0, s));
      return 0;
    }
    

    B

    有一个结论是如果任意点集 (V) 都满足 (E(V) le 2|V| - 2),那么这个图就是丛林,反之则不是,可以用拟阵并证明。

    那么就很好做了,建一个二分图,边向点连边,边权值是 (1),点权值是 (-2),跑最大权闭合子图即可。

    这样有一个问题是最大权闭合子图权值可能是负的,这个时候网络流会跑出一个空集来,于是你需要强制选一个点(把它的权值改成 (0))。

    每个点都跑一遍 Dinic 显然不优,换成退流即可。

    #include <bits/stdc++.h>
    
    #define IL __inline__ __attribute__((always_inline))
    
    #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
    #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
    #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
    #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
    
    typedef long long LL;
    
    template <class T>
    IL bool chkmax(T &a, const T &b) {
      return a < b ? ((a = b), 1) : 0;
    }
    
    template <class T>
    IL bool chkmin(T &a, const T &b) {
      return a > b ? ((a = b), 1) : 0;
    }
    
    template <class T>
    IL T mymax(const T &a, const T &b) {
      return a > b ? a : b;
    }
    
    template <class T>
    IL T mymin(const T &a, const T &b) {
      return a < b ? a : b;
    }
    
    template <class T>
    IL T myabs(const T &a) {
      return a > 0 ? a : -a;
    }
    
    const int INF = 0X3F3F3F3F;
    const double EPS = 1E-8, PI = acos(-1.0);
    
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define OK DEBUG("Passing [%s] in LINE %d...
    ", __FUNCTION__, __LINE__)
    #define SZ(x) ((int)(x).size())
    
    const int MAXN = 6000 + 5, MAXM = 100000 + 5;
    
    namespace NetworkFlow {
    int s, t, n, m;
    
    struct Edge {
      int from, to, resi;
    
      Edge() {}
      Edge(int _f, int _t, int _r) : from(_f), to(_t), resi(_r) {}
    } edge[MAXM * 2];
    
    std::vector<int> adj[MAXN];
    int cnt;
    
    IL void addEdge(int u, int v, int c) {
      edge[cnt] = Edge(u, v, c), adj[u].push_back(cnt);
      ++ cnt;
      edge[cnt] = Edge(v, u, 0), adj[v].push_back(cnt);
      ++ cnt;
    }
    
    IL void build() {
      scanf("%d%d", &n, &m);
      s = n + m + 1, t = n + m + 2;
      For(i, 1, n) {
        addEdge(i, t, 2);
      }
      For(i, 1, m) {
        addEdge(s, i + n, 1);
      }
      For(i, 1, m) {
        int u, v;
        scanf("%d%d", &u, &v);
        addEdge(i + n, u, INF);
        addEdge(i + n, v, INF);
      }
    }
    
    int dist[MAXN], vis[MAXN], rc;
    
    IL bool BFS() {
      static int queue[MAXN];
      dist[s] = 0;
      vis[s] = ++ rc;
      int l = 1, r = 0;
      queue[++ r] = s;
      while (l <= r) {
        int u = queue[l ++];
        for (auto &x : adj[u]) {
          Edge &e = edge[x];
          if (e.resi && vis[e.to] != rc) {
            dist[e.to] = dist[u] + 1;
            vis[e.to] = rc;
            queue[++ r] = e.to;
          } 
        }
      }
      return vis[t] == rc;
    }
    
    int cur[MAXN];
    
    int DFS(int u, int x) {
      if (!x || u == t) {
        return x;
      }
      int flow = 0, f;
      for (int &i = cur[u]; i < SZ(adj[u]); ++ i) {
        Edge &e = edge[adj[u][i]];
        if (dist[e.to] == dist[u] + 1 && (f = DFS(e.to, mymin(e.resi, x)))) {
          edge[adj[u][i]].resi -= f, edge[adj[u][i] ^ 1].resi += f;
          flow += f, x -= f;
          if (!x) {
            break;
          }
        }
      }
      return flow;
    }
    
    IL int dinic(int p = s, int q = t, int init = INF) {
      if (p == q) {
        return init;
      }
      int flow = 0, a = s, b = t;
      s = p, t = q;
      while (init > flow && BFS()) {
        memset(cur, 0, sizeof cur);
        flow += DFS(s, init - flow);
      }
      s = a, t = b;
      return flow;
    }
    
    IL bool solve() {
      int w = dinic();
      if (w < m) {
        return 0;
      }
      For(i, 1, n) {
        int a = (i - 1) << 1, b = (i - 1) << 1 | 1, u = edge[a].from, v = edge[a].to, p = edge[b].resi;
        dinic(t, v, p), dinic(u, s, p);
        w -= p;
        edge[a].resi = edge[b].resi = 0;
        w += dinic(s, t, 2);
        if (w < m) {
          return 0;
        }
        edge[a].resi = 2;
      }
      return 1;
    }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("forest.in", "r", stdin);
    #endif
      NetworkFlow::build();
      puts(NetworkFlow::solve() ? "Yes" : "No");
      return 0;
    }
    

    C

    参照吉如一的集训队论文,用 Segment Tree Beats 的方法维护操作 2,其他操作把区间的最小值和非最小值部分分开维护就行了。

    #include <bits/stdc++.h>
    
    #define IL __inline__ __attribute__((always_inline))
    
    #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
    #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
    #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
    #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
    
    typedef long long LL;
    
    template <class T>
    IL bool chkmax(T &a, const T &b) {
      return a < b ? ((a = b), 1) : 0;
    }
    
    template <class T>
    IL bool chkmin(T &a, const T &b) {
      return a > b ? ((a = b), 1) : 0;
    }
    
    template <class T>
    IL T mymax(const T &a, const T &b) {
      return a > b ? a : b;
    }
    
    template <class T>
    IL T mymin(const T &a, const T &b) {
      return a < b ? a : b;
    }
    
    template <class T>
    IL T myabs(const T &a) {
      return a > 0 ? a : -a;
    }
    
    const int INF = 0X3F3F3F3F;
    const double EPS = 1E-8, PI = acos(-1.0);
    
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define OK DEBUG("Passing [%s] in LINE %d...
    ", __FUNCTION__, __LINE__)
    #define SZ(x) ((int)(x).size())
    
    struct Input {
      char buf[1 << 25], *s;
    
      Input() {
    #ifndef ONLINE_JUDGE
        freopen("array.in", "r", stdin);
        freopen("array.out", "w", stdout);
    #endif
        fread(s = buf, 1, 1 << 25, stdin);
      }
    
      friend Input &operator>>(Input &io, int &x) {
        x = 0;
        int p = 1;
        while (!isdigit(*io.s)) {
          if (*io.s == '-') {
            p = -1;
          }
          ++ io.s;
        }
        while (isdigit(*io.s)) {
          x =  x * 10 + *io.s ++ - '0';
        }
        x *= p;
        return io;
      }
    } cin;
    
    const int MAXN = 500000 + 5;
    
    struct SegmentTree {
      using Arr = std::array<int, MAXN * 4>;
    
      Arr min, min_num, min_mark, sec, mark, min_hmin, min_pmark, hmin, pmark;
    
    #define lc (o << 1)
    #define rc (o << 1 | 1)
      void pushUp(int o, int l, int r) {
        int mid = (l + r) >> 1;
        min_mark[o] = mark[o] = min_pmark[o] = pmark[o] = 0;
        if (min[lc] < min[rc]) {
          min[o] = min[lc], min_num[o] = min_num[lc];
          min_hmin[o] = min_hmin[lc], hmin[o] = min_hmin[rc];
          if (min_num[lc] != mid - l + 1) {
            chkmin(hmin[o], hmin[lc]);
          }
          if (min_num[rc] != r - mid) {
            chkmin(hmin[o], hmin[rc]);
          }
          sec[o] = min_num[lc] == mid - l + 1 ? min[rc] : mymin(sec[lc], min[rc]);
        } else if (min[lc] > min[rc]) {
          min[o] = min[rc], min_num[o] = min_num[rc];
          min_hmin[o] = min_hmin[rc], hmin[o] = min_hmin[lc];
          if (min_num[lc] != mid - l + 1) {
            chkmin(hmin[o], hmin[lc]);
          }
          if (min_num[rc] != r - mid) {
            chkmin(hmin[o], hmin[rc]);
          }
          sec[o] = min_num[rc] == r - mid ? min[lc] : mymin(sec[rc], min[lc]);
        } else {
          min[o] = min[lc], min_num[o] = min_num[lc] + min_num[rc];
          min_hmin[o] = mymin(min_hmin[lc], min_hmin[rc]);
          if (min_num[lc] != mid - l + 1 && min_num[rc] != r - mid) {
            hmin[o] = mymin(hmin[lc], hmin[rc]);
          } else if (min_num[lc] != mid - l + 1) {
            hmin[o] = hmin[lc];
          } else if (min_num[rc] != r - mid) {
            hmin[o] = hmin[rc];
          } else {
            hmin[o] = 0;
          }
          if (min_num[lc] == mid - l + 1) {
            sec[o] = sec[rc];
          } else if (min_num[rc] == r - mid) {
            sec[o] = sec[lc];
          } else {
            sec[o] = mymin(sec[lc], sec[rc]);
          }
        }
      }
    
      void pushDown(int o, int l, int r) {
        int mid = (l + r) >> 1;
        if (min_pmark[o]) {
          if (min[lc] < min[rc]) {
            chkmin(min_hmin[lc], min[lc] + min_pmark[o]);
            chkmin(min_pmark[lc], min_mark[lc] + min_pmark[o]);
          } else if (min[lc] < min[rc]) {
            chkmin(min_hmin[rc], min[rc] + min_pmark[o]);
            chkmin(min_pmark[rc], min_mark[rc] + min_pmark[o]);
          } else {
            chkmin(min_hmin[lc], min[lc] + min_pmark[o]), chkmin(min_hmin[rc], min[rc] + min_pmark[o]);
            chkmin(min_pmark[lc], min_mark[lc] + min_pmark[o]), chkmin(min_pmark[rc], min_mark[rc] + min_pmark[o]);
          }
          min_pmark[o] = 0;
        }
        if (pmark[o]) {
          if (min[lc] < min[rc]) {
            chkmin(min_hmin[rc], min[rc] + pmark[o]);
            chkmin(min_pmark[rc], min_mark[rc] + pmark[o]);
          } else if (min[lc] > min[rc]) {
            chkmin(min_hmin[lc], min[lc] + pmark[o]);
            chkmin(min_pmark[lc], min_mark[lc] + pmark[o]);
          }
          if (min_num[lc] != mid - l + 1) {
            chkmin(hmin[lc], sec[lc] + pmark[o]);
            chkmin(pmark[lc], mark[lc] + pmark[o]);
          }
          if (min_num[rc] != r - mid) {
            chkmin(hmin[rc], sec[rc] + pmark[o]);
            chkmin(pmark[rc], mark[rc] + pmark[o]);
          }
          pmark[o] = 0;
        }
        int x = min[lc], y = min[rc];
        if (min_mark[o]) {
          if (x < y) {
            min[lc] += min_mark[o], min_mark[lc] += min_mark[o];
          } else if (x > y) {
            min[rc] += min_mark[o], min_mark[rc] += min_mark[o];
          } else {
            min[lc] += min_mark[o], min[rc] += min_mark[o], min_mark[lc] += min_mark[o], min_mark[rc] += min_mark[o];
          }
          min_mark[o] = 0;
        }
        if (mark[o]) {
          if (x < y) {
            min[rc] += mark[o], min_mark[rc] += mark[o];
          } else if (x > y) {
            min[lc] += mark[o], min_mark[lc] += mark[o];
          }
          if (min_num[lc] != mid - l + 1) {
            sec[lc] += mark[o], mark[lc] += mark[o];
          }
          if (min_num[rc] != r - mid) {
            sec[rc] += mark[o], mark[rc] += mark[o];
          }
          mark[o] = 0;
        }
      }
    
      void build(int o, int l, int r, int *a) {
        if (l == r) {
          min[o] = min_hmin[o] = a[l];
          min_num[o] = 1;
          return;
        }
        int mid = (l + r) >> 1;
        build(lc, l, mid, a);
        build(rc, mid + 1, r, a);
        pushUp(o, l, r);
      }
    
      void modify1(int o, int l, int r, int a, int b, int x) {
        if (l >= a && r <= b) {
          min[o] += x, min_mark[o] += x;
          chkmin(min_hmin[o], min[o]), chkmin(min_pmark[o], min_mark[o]);
          if (min_num[o] != r - l + 1) {
            sec[o] += x, mark[o] += x;
            chkmin(hmin[o], sec[o]), chkmin(pmark[o], mark[o]); 
          }
          return;
        }
        pushDown(o, l, r);
        int mid = (l + r) >> 1;
        if (a <= mid) {
          modify1(lc, l, mid, a, b, x);
        }
        if (b > mid) {
          modify1(rc, mid + 1, r, a, b, x);
        }
        pushUp(o, l, r);
      }
    
      void modify2(int o, int l, int r, int a, int b, int x) {
        if (l >= a && r <= b) {
          if (x <= min[o]) {
            return;
          } else if (min_num[o] == r - l + 1 || x < sec[o]) {
            int d = x - min[o];
            min[o] += d, min_mark[o] += d;
            chkmin(min_hmin[o], min[o]), chkmin(min_pmark[o], min_mark[o]);
            return;
          }
        }
        pushDown(o, l, r);
        int mid = (l + r) >> 1;
        if (a <= mid) {
          modify2(lc, l, mid, a, b, x);
        }
        if (b > mid) {
          modify2(rc, mid + 1, r, a, b, x);
        }
        pushUp(o, l, r);
      }
    
      int query1(int o, int l, int r, int a, int b) {
        if (l >= a && r <= b) {
          return min[o];
        }
        pushDown(o, l, r);
        int mid = (l + r) >> 1, ans = INT_MAX;
        if (a <= mid) {
          chkmin(ans, query1(lc, l, mid, a, b));
        }
        if (b > mid) {
          chkmin(ans, query1(rc, mid + 1, r, a, b));
        }
        return ans;
      }
    
      int query2(int o, int l, int r, int a, int b) {
        if (l >= a && r <= b) {
          return min_num[o] == r - l + 1 ? min_hmin[o] : mymin(min_hmin[o], hmin[o]);
        }
        pushDown(o, l, r);
        int mid = (l + r) >> 1, ans = INT_MAX;
        if (a <= mid) {
          chkmin(ans, query2(lc, l, mid, a, b));
        }
        if (b > mid) {
          chkmin(ans, query2(rc, mid + 1, r, a, b));
        }
        return ans;
      }
    } seg;
    
    int a[MAXN];
    
    int main() {
      int n, m;
      cin >> n >> m;
      For(i, 1, n) {
        cin >> a[i];
      }
      seg.build(1, 1, n, a);
      For(i, 1, m) {
        int opt;
        cin >> opt;
        if (opt == 1) {
          int l, r, c;
          cin >> l >> r >> c;
          seg.modify1(1, 1, n, l, r, c);
        } else if (opt == 2) {
          int l, r, d;
          cin >> l >> r >> d;
          seg.modify2(1, 1, n, l, r, d);
        } else if (opt == 3) {
          int l, r;
          cin >> l >> r;
          printf("%d
    ", seg.query1(1, 1, n, l, r));
        } else {
          int l, r;
          cin >> l >> r;
          printf("%d
    ", seg.query2(1, 1, n, l, r));
        }
      }
      return 0;
    }
    
  • 相关阅读:
    CF 1006C Three Parts of the Array【双指针/前缀和/后缀和/二分】
    经验笔记二
    CF 1006B Polycarp's Practice【贪心】
    CF 1003D Coins and Queries【位运算/硬币值都为2的幂/贪心】
    CF 1003C Intense Heat【前缀和/精度/双层暴力枚举】
    CF 1003B Binary String Constructing 【构造/找规律/分类讨论】
    CF 1005C Summarize to the Power of Two 【hash/STL-map】
    CF 1005B Delete from the Left 【模拟数组操作/正难则反】
    CF 1005A Tanya and Stairways 【STL】
    CF 1009A Game Shopping 【双指针/模拟】
  • 原文地址:https://www.cnblogs.com/sjkmost/p/12190195.html
Copyright © 2011-2022 走看看