• 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;
    }

     
  • 相关阅读:
    keyCode对照表
    WebApi的前端调用
    AJAX get和post请求
    Linq中常用语法
    MVC三种分页方法
    常用DBhelper封装方法
    ASP.NET MVC 导入Excel文件(完整版)
    Razor语法2
    MVC之路由规则 (自定义,约束,debug)
    MVC
  • 原文地址:https://www.cnblogs.com/yyf0309/p/ur11.html
Copyright © 2020-2023  润新知