zoukankan      html  css  js  c++  java
  • UOJ Round #11 简要题解

    从这里开始

      说好的 agc 045 题解去哪了

    Problem A 元旦老人与汉诺塔

      直接状压每个盘子在哪个柱子,记忆化搜索即可。

      时间复杂度 O(能过)。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    #define ull __int128
    
    const int Mod = 998244353;
    
    int n, m;
    
    typedef class Status {
      public:
        ull a, b, c;
        int step;
    
        Status() {  }
        Status(ull a, ull b, ull c, int step) : a(a), b(b), c(c), step(step) { }
    
        void read() {
          for (int i = 0, x; i < n; i++) {
            scanf("%d", &x);
            if (x == 1) {
              a |= 1ull << i;
            } else if (x == 2) {
              b |= 1ull << i;
            } else {
              c |= 1ull << i;
            }
          }
        }
        bool operator < (Status t) const {
          if (a ^ t.a)  return a < t.a;
          if (b ^ t.b)  return b < t.b;
          if (c ^ t.c)  return c < t.c;
          return step < t.step;
        }
    
        bool equal(Status t) {
          return a == t.a && b == t.b && c == t.c;
        }
    } Status;
    
    Status ss, st;
    map<Status, int> f; 
    
    void inc(int& x) {
      if (x >= Mod) {
        x -= Mod;
      }
    }
    
    int F(Status s) {
      if (s.step > m) {
        return 0;
      }
      if (f.count(s)) {
        return f[s];
      }
      ull a = s.a & (-s.a);
      ull b = s.b & (-s.b);
      ull c = s.c & (-s.c);
      int ret = s.equal(st);
      if (a) {
        if (a < b || !b) inc(ret += F(Status(s.a ^ a, s.b ^ a, s.c, s.step + 1)));
        if (a < c || !c) inc(ret += F(Status(s.a ^ a, s.b, s.c ^ a, s.step + 1)));
      }
      if (b) {
        if (b < a || !a) inc(ret += F(Status(s.a ^ b, s.b ^ b, s.c, s.step + 1)));
        if (b < c || !c) inc(ret += F(Status(s.a, s.b ^ b, s.c ^ b, s.step + 1)));
      }
      if (c) {
        if (c < a || !a) inc(ret += F(Status(s.a ^ c, s.b, s.c ^ c, s.step + 1)));
        if (c < b || !b) inc(ret += F(Status(s.a, s.b ^ c, s.c ^ c, s.step + 1)));
      }
      return f[s] = ret;
    }
    
    int main() {
      scanf("%d%d", &n, &m);
      ss.read();
      st.read();
      int ans = F(ss);
      printf("%d
    ", ans);
    	return 0;
    }

    Problem B 元旦老人与丛林

      注意到一个必要条件是任意一个点集 $V$ 的导出子图的边集大小不会超过 $2|V| - 2$。可以证明这个是充分的。

      证明考虑归纳法,当 $n = 1$ 的时候显然满足。

      现在考虑 $n > 1$ 的情况,并假设 $n$ 更小的时候成立。

      考虑图中度数最小的 $x$,那么 $x$ 的度数只可能为 $0, 1, 2, 3$。

      对于前 3 种情况可以简单地分配与它相邻的边使得它在 2 个新图中的度数均不超过 1。下面找考虑 $x$ 的度数为 3 的情况。

      我们称一个子图 $G = (V, E)$ 是满的,当且仅当 $2|V| - 2 = |E|$。

    引理 如果 $G_1 = (V_1, E_1), G_2 = (V_2, E_2)$ 都是满子图,并且 $V_1 cap V_2 eq nothing$,那么 $G = (V_1 cup V_2, E_1 cup E_2), G_3  = (V_1 cap V_2, E_1 cap E_2)$ 都是满子图。

      证明  $|E_1 cup E_2| = |E_1| + |E_2| - |E_1cap E_2| geqslant 2|V_1| - 2 + 2|V_2| - 2 - (2|V_1cap V_2| - 2) = 2|V_1 cup V_2| - 2$,又因为 $|E_1 cup E_2| leqslant 2|V_1 cup V_2| - 2$,所以有 $|E_1 cup E_2| =2|V_1 cup V_2| - 2$。

      用类似的方法可以证得 $G_3$ 是满子图。

      考虑和 $x$ 相邻的三个点 $a, b, c$。设删掉 $x$ 及其相邻的边后得到的图是 $G'$。

    定理 $(a, b), (b, c), (a, c)$ 中至少存在一对 $(u, v)$ 满足同时包含 $(u, v)$ 的导出子图都不是满子图 

      证明 考虑反证法,在这三对各找一个使得它是满子图的子图,然后把它们并起来,这样得到了一个同时包含 $a, b, c$ 的满子图,这时候加入 $x$ 和它相邻的边,显然此时不满足条件。

      假设 $G'$ 中同时包含 $a, b$ 的导出子图都不是满子图,那么在 $G'$ 中加入边 $(a,b)$ 得到 $G''$,然后根据归纳假设有 $G''$ 是丛林。因此我们得到了两个森林,在包含 $(a, b)$ 的边的森林中,删除 $(a, b)$,然后加入 $(x, a), (x, b)$,再在另外一边加入 $(x, c)$。

      剩下的问题是判断是否存在一个点集 $V$,它导出的边集 $E$,满足 $frac{|E|}{|V| - 1} > 2$。

      直接最大权闭合子图有点问题,因为它可能 $|V|$ 选空集,然后这样就会 GG。

      每次硬点一个点必须选,退流就可以了。

      时间复杂度 $O(nm)$。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    const int inf = (signed) (~0u >> 2);
    
    typedef class Edge {
    	public:
    		int ed, nx, r;
    
    		Edge() {	}
    		Edge(int ed, int nx, int r) : ed(ed), nx(nx), r(r) {	}
    } Edge;
    
    typedef class MapManager {
    	public:
    		vector<int> h;
    		vector<Edge> E;
    		
    		MapManager() {	}
    		MapManager(int n) {
    			h.assign(n + 1, -1);
    		}
    		void add_edge(int u, int v, int c) {
    			E.emplace_back(v, h[u], c);
    			h[u] = (signed) E.size() - 1;
    		}
    
    		Edge& operator [] (int p) {
    			return E[p];
    		}
    } MapManager;
    
    typedef class Network {
    	public:
    		int S, T;
    		MapManager g;
    		vector<int> div;
    		int rest_flow;
    		
    		Network() {	}
    		Network(int S, int T) : S(S), T(T), g(T + 1) {
    			div.resize(T + 1);
    		}
    
    		bool bfs() {
    			queue<int> Q;
    			fill(div.begin(), div.end(), -1);
    			Q.push(S);
    			div[S] = 0;
    			while (!Q.empty()) {
    				int p = Q.front();
    				Q.pop();
    				if (p == T) {
    					continue;
    				}
    				for (int i = g.h[p]; ~i; i = g[i].nx) {
    					int e = g[i].ed;
    					if (!g[i].r || ~div[e]) {
    						continue;
    					}
    					div[e] = div[p] + 1;
    					Q.push(e);
    				}
    			}
    			return div[T] != -1;
    		}
    
    		vector<int> cur;
    		int dfs(int p, int mf) {
    			if (p == T || !mf) {
    				rest_flow -= mf;
    				if (!rest_flow) {
    					throw 1;
    				}
    				return mf;
    			}
    			int flow = 0, f;
    			for (int& i = cur[p]; ~i; i = g[i].nx) {
    				int e = g[i].ed;
    				if (div[e] == div[p] + 1 && (f = dfs(e, min(mf, g[i].r))) > 0) {
    					flow += f;
    					g[i].r -= f;
    					g[i ^ 1].r += f;
    					mf -= f;
    					if (!mf) {
    						break;
    					}
    				}
    			}
    			return flow;
    		}
    
    		int dinic() {
    			int ret = 0;
    			try {
    				while (bfs()) {
    					cur = g.h;
    					ret += dfs(S, inf);
    				}
    			} catch (int) {
    				return 2;
    			}
    			return ret;
    		}
    		
    		void add_edge(int u, int v, int c) {
    			g.add_edge(u, v, c);
    			g.add_edge(v, u, 0);
    		}
    
    		vector<bool> get_S() {
    			vector<bool> vis (T + 1, false);
    			queue<int> Q;
    			Q.push(S);
    			vis[S] = true;
    			while (!Q.empty()) {
    				int p = Q.front();
    				Q.pop();
    				for (int i = g.h[p]; ~i; i = g[i].nx) {
    					int e = g[i].ed;
    					if (!vis[e] && g[i].r) {
    						vis[e] = true;
    						Q.push(e);
    					}
    				}
    			}
    			return vis;
    		}
    } Network;
    
    int n, m, lim;
    
    int main() {
    	scanf("%d%d", &n, &m);
    	lim = 2;
    	int T;
    	Network network(0, T = n + m + 1);
    	vector<int> deg (n + 1, 0);
    	vector<pair<int, int>> E (m);
    	for (int i = 0, u, v; i < m; i++) {
    		scanf("%d%d", &u, &v);
    		if (u == v) {
    			puts("No");
    			return 0;
    		}
    		E[i] = make_pair(u, v);
    		++deg[u];
    		++deg[v];
    	}
    	for (int i = 1; i <= n; i++) {
    		if (deg[i] >= lim) {
    			network.add_edge(i, T, lim);
    		}
    	}
    	int cost = 0;
    	for (int i = 1, u, v; i <= m; i++) {
    		u = E[i - 1].first, v = E[i - 1].second;
    		if (deg[u] >= lim && deg[v] >= lim) {
    			network.add_edge(0, n + i, 1);
    			network.add_edge(n + i, u, inf);
    			network.add_edge(n + i, v, inf);
    			++cost;
    		}
    	}
    	network.rest_flow = inf;
    	cost -= network.dinic();
    	if (cost) {
    		puts("No");
    		return 0;
    	} else {
    		auto inS = network.get_S();
    		for (int i = 1; i <= n; i++) {
    			if (inS[i] && deg[i] >= lim) {
    				puts("No");
    				return 0;
    			}
    		}
    		for (int i = 1; i <= n; i++) {
    			if (deg[i] < lim) {
    				continue;
    			}
    			Network network1 = network;
    			network1.add_edge(0, i, lim);
    			network1.rest_flow = 2;
    			int xx = network1.dinic();
    			if (xx < lim) {
    				puts("No");
    				return 0;
    			}
    		}
    	}
    	puts("Yes");
    	return 0;
    }

    Problem C 元旦老人与数列

      若干 segment tree beats 板题之一。

      考虑 segment tree beats 本质上是对区间的最小值打标记。当最小值集合发生改变的时候暴力递归。

      所以对最小值和非区间最小值分别维护区间加标记。

      因为要查询区间历史最小值,所以再维护一下历史最小值,以及最小值和非最小值的加标记的最小前缀和。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    typedef class Input {
      protected:
        const static int limit = 65536;
        FILE* file; 
    
        int ss, st;
        char buf[limit];
      public:
    
        Input() : file(NULL)	{	};
        Input(FILE* file) : file(file) {	}
    
        void open(FILE *file) {
          this->file = file;
        }
    
        void open(const char* filename) {
          file = fopen(filename, "r");
        }
    
        char pick() {
          if (ss == st)
            st = fread(buf, 1, limit, file), ss = 0;//, cerr << "str: " << buf << "ed " << st << endl;
          return buf[ss++];
        }
    } Input;
    
    #define digit(_x) ((_x) >= '0' && (_x) <= '9')
    
    Input& operator >> (Input& in, unsigned& u) {
      char x;
      while (~(x = in.pick()) && !digit(x));
      for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
      return in;
    }
    
    Input& operator >> (Input& in, unsigned long long& u) {
      char x;
      while (~(x = in.pick()) && !digit(x));
      for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
      return in;
    }
    
    Input& operator >> (Input& in, int& u) {
      char x;
      while (~(x = in.pick()) && !digit(x) && x != '-');
      int aflag = ((x == '-') ? (x = in.pick(), -1) : (1));
      for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
      u *= aflag;
      return in;
    }
    
    Input& operator >> (Input& in, long long& u) {
      char x;
      while (~(x = in.pick()) && !digit(x) && x != '-');
      int aflag = ((x == '-') ? (x = in.pick(), -1) : (1));
      for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
      u *= aflag;
      return in;
    }
    
    Input& operator >> (Input& in, double& u) {
      char x;
      while (~(x = in.pick()) && !digit(x) && x != '-');
      int aflag = ((x == '-') ? (x = in.pick(), -1) : (1));
      for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
      if (x == '.') {
        double dec = 1;
        for ( ; ~(x = in.pick()) && digit(x); u = u + (dec *= 0.1) * (x - '0'));
      }
      u *= aflag;
      return in;
    }
    
    Input& operator >> (Input& in, char* str) {
      char x;
      while (~(x = in.pick()) && x != '
    ' && x != ' ')
        *(str++) = x;
      *str = 0;
      return in;
    }
    
    Input in (stdin);
    
    typedef class Output {
      protected:
        const static int Limit = 65536;
        char *tp, *ed;
        char buf[Limit];
        FILE* file;
        int precision;
    
        void flush() {
          fwrite(buf, 1, tp - buf, file);
          fflush(file);
          tp = buf;
        }
    
      public:
    
        Output() {	}
        Output(FILE* file) : tp(buf), ed(buf + Limit), file(file), precision(6) {	}
        Output(const char *str) : tp(buf), ed(buf + Limit), precision(6) {
          file = fopen(str, "w");
        }
        ~Output() {
          flush();
        }
    
        void put(char x) {
          if (tp == ed)
            flush();
          *(tp++) = x;
        }
    
        int get_precision() {
          return precision;
        }
        void set_percision(int x) {
          precision = x;
        }
    } Output;
    
    Output& operator << (Output& out, int x) {
      static char buf[35];
      static char * const lim = buf + 34;
      if (!x)
        out.put('0');
      else {
        if (x < 0)
          out.put('-'), x = -x;
        char *tp = lim;
        for ( ; x; *(--tp) = x % 10, x /= 10);
        for ( ; tp != lim; out.put(*(tp++) + '0'));
      }
      return out;
    }
    
    Output& operator << (Output& out, long long x) {
      static char buf[36];
      static char * const lim = buf + 34;
      if (!x)
        out.put('0');
      else {
        if (x < 0)
          out.put('-'), x = -x;
        char *tp = lim;
        for ( ; x; *(--tp) = x % 10, x /= 10);
        for ( ; tp != lim; out.put(*(tp++) + '0'));
      }
      return out;
    }
    
    Output& operator << (Output& out, unsigned x) {
      static char buf[35];
      static char * const lim = buf + 34;
      if (!x)
        out.put('0');
      else {
        char *tp = lim;
        for ( ; x; *(--tp) = x % 10, x /= 10);
        for ( ; tp != lim; out.put(*(tp++) + '0'));
      }
      return out;
    }
    
    Output& operator << (Output& out, char x)  {
      out.put(x);
      return out;
    }
    
    Output& operator << (Output& out, const char* str) {
      for ( ; *str; out.put(*(str++)));
      return out;
    }
    
    Output& operator << (Output& out, double x) {
      int y = x;
      x -= y;
      out << y << '.';
      for (int i = out.get_precision(); i; i--, y = x * 10, x = x * 10 - y, out.put(y + '0'));
      return out;
    }
    
    Output out (stdout);
    
    const int N = 5e5 + 5;
    const int inf = (~0u >> 1);
    
    #define ll long long
    
    typedef class SegTreeNode {
      public:
        int mi, mi2;
        int tga, tga2;
        int hmi, mtga, mtga2;
        SegTreeNode *l, *r;
      
        void init(int x) {
          mi = x;
          mi2 = inf;
          hmi = x;
          tga = tga2 = mtga = mtga2 = 0;
          l = r = NULL;
        }
    
        void upd(int _tga, int _tga2, int _mtga, int _mtga2) {
          hmi = min(hmi, mi + _mtga);
          mi += _tga;
          (mi2 != inf) && (mi2 += _tga2, 0);
          mtga = min(mtga, tga + _mtga);
          mtga2 = min(mtga2, tga2 + _mtga2);
          tga += _tga;
          tga2 += _tga2;
        }
        void upd(int v) {
          if (v >= mi2) {
            push_down();
            l->upd(v);
            r->upd(v);
            push_up();
          } else if (v > mi) {
            tga += v - mi;
            mtga = min(mtga, tga);
            mi = v;
          }
        }
    
        void push_up() {
          hmi = min(l->hmi, r->hmi);
          mi = min(l->mi, r->mi);
          if (l->mi == r->mi) {
            mi2 = min(l->mi2, r->mi2);
          } else if (l->mi < r->mi) {
            mi2 = min(l->mi2, r->mi);
          } else {
            mi2 = min(l->mi, r->mi2);
          }
        }
        void push_down() {
          if (tga || tga2 || mtga || mtga2) {
            if (l->mi + tga == mi) {
              l->upd(tga, tga2, mtga, mtga2);
            } else {
              l->upd(tga2, tga2, mtga2, mtga2);
            }
            if (r->mi + tga == mi) {
              r->upd(tga, tga2, mtga, mtga2);
            } else {
              r->upd(tga2, tga2, mtga2, mtga2);
            }
            tga = tga2 = mtga = mtga2 = 0;
          }
        }
    } SegTreeNode;
    
    SegTreeNode pool[N << 1];
    SegTreeNode* _top = pool;
    
    typedef class SegmentTree {
      public:
        int n;
        SegTreeNode* rt;
    
        void build(SegTreeNode*& p, int l, int r, int* a) {
          p = _top++;
          if (l == r) {
            p->init(a[l]);
          } else {
            int mid = (l + r) >> 1;
            build(p->l, l, mid, a);
            build(p->r, mid + 1, r, a);
            p->push_up();
          }
        }
        void build(int n, int* a) {
          this->n = n;
          build(rt, 1, n, a);
        }
    
        void update_add(SegTreeNode* p, int l, int r, int ql, int qr, int a) {
          if (l == ql && r == qr) {
            p->upd(a, a, a, a);
            return;
          }
          p->push_down();
          int mid = (l + r) >> 1;
          if (qr <= mid) {
            update_add(p->l, l, mid, ql, qr, a);
          } else if (ql > mid) {
            update_add(p->r, mid + 1, r, ql, qr, a);
          } else {
            update_add(p->l, l, mid, ql, mid, a);
            update_add(p->r, mid + 1, r, mid + 1, qr, a);
          }
          p->push_up();
        }
        void update_add(int l, int r, int a) {
          update_add(rt, 1, n, l, r, a);
        }
    
        void update_mx(SegTreeNode* p, int l, int r, int ql, int qr, int v) {
          if (l == ql && r == qr) {
            p->upd(v);
            return;
          }
          p->push_down();
          int mid = (l + r) >> 1;
          if (qr <= mid) {
            update_mx(p->l, l, mid, ql, qr, v);
          } else if (ql > mid) {
            update_mx(p->r, mid + 1, r, ql, qr, v);
          } else {
            update_mx(p->l, l, mid, ql, mid, v);
            update_mx(p->r, mid + 1, r, mid + 1, qr, v);
          }
          p->push_up();
        }
        void update_mx(int l, int r, int v) {
          update_mx(rt, 1, n, l, r, v);
        }
    
        int query_mi(SegTreeNode* p, int l, int r, int ql, int qr) {
          if (l == ql && r == qr) {
            return p->mi;
          }
          p->push_down();
          int mid = (l + r) >> 1;
          if (qr <= mid) {
            return query_mi(p->l, l, mid, ql, qr);
          } else if (ql > mid) {
            return query_mi(p->r, mid + 1, r, ql, qr);
          }
          int a = query_mi(p->l, l, mid, ql, mid);
          int b = query_mi(p->r, mid + 1, r, mid + 1, qr);
          return min(a, b);
        }
        int query_mi(int l, int r) {
          return query_mi(rt, 1, n, l, r);
        }
    
        int query_hmi(SegTreeNode* p, int l, int r, int ql, int qr) {
          if (l == ql && r == qr) {
            return p->hmi;
          }
          p->push_down();
          int mid = (l + r) >> 1;
          if (qr <= mid) {
            return query_hmi(p->l, l, mid, ql, qr);
          } else if (ql > mid) {
            return query_hmi(p->r, mid + 1, r, ql, qr);
          }
          int a = query_hmi(p->l, l, mid, ql, mid);
          int b = query_hmi(p->r, mid + 1, r, mid + 1, qr);
          return min(a, b);
        }
        int query_hmi(int l, int r) {
          return query_hmi(rt, 1, n, l, r);
        }
    } SegmentTree;
    
    int n, m;
    int a[N];
    SegmentTree st;
    
    int main() {
      in >> n >> m;
      for (int i = 1; i <= n; i++) {
        in >> a[i];
      }
      st.build(n, a);
      int op, l, r, x;
      while (m--) {
        in >> op >> l >> r;
        if (op <= 2) {
          in >> x;
          if (op == 1) {
            st.update_add(l, r, x);
          } else{
            st.update_mx(l, r, x);
          } 
        } else if (op == 3) {
          out << st.query_mi(l, r) << '
    ';
        } else {
          out << st.query_hmi(l, r) << '
    ';
        }
      }
      return 0;
    }

     
  • 相关阅读:
    67. Add Binary
    66. Plus One
    64. Minimum Path Sum
    63. Unique Paths II
    How to skip all the wizard pages and go directly to the installation process?
    Inno Setup打包之先卸载再安装
    How to change the header background color of a QTableView
    Openstack object list 一次最多有一万个 object
    Openstack 的 Log 在 /var/log/syslog 里 【Ubuntu】
    Git 分支
  • 原文地址:https://www.cnblogs.com/yyf0309/p/ur11.html
Copyright © 2011-2022 走看看