zoukankan      html  css  js  c++  java
  • Namori[agc004F]

    Description

    ​ 现在给你一张\(N\)个点\(M\)条边的连通图,我们保证\(N−1\leqslant M \leqslant N\),且无重边和自环。

    ​ 每一个点都有一种颜色,非黑即白。初始时,所有点都是白色的。

    ​ “全”想通过执行若干次某种操作的方式,来将所有的点变成黑色。操作方式如下:

    ​ 选择一对颜色相同的相邻的节点(存在边直接连接彼此),将它们的颜色反转。即若原来都是白色,则都变成黑色,反之亦然。

    ​ 现在“全”想知道,他能否通过执行这种操作以达到目的。如果可以,他还希望步数尽可能的少。

    Hint

    \[2 \leqslant N\leqslant 10^5, N−1\leqslant M \leqslant N \]

    Solution

    ​ 发现\(N−1\leqslant M \leqslant N\)所以原图要么是一棵树要么是一颗环套树(只有一个环)。

    树的做法

    ​ 我们考虑转换模型,注意到树是一个二分图,所以我们将树分成奇数层和偶数层,奇数层有一个空位,而偶数层有一个棋子,那么将边的颜色反转的过程可以看成将棋子进行移动。那么可以发现仅当空位数=硬币数时问题有解。

    ​ 然后,考虑最小步数,我们记硬币为-1,空位为1,\(S_i\)表示子树和,那么\(K=\sum_{i=1}^{n}{Si}\),考虑意义\(S_i\)表示的是\(i\to u\)这条边的贡献,发现K为原问题答案的下界。

    ​ 又因为对于\(\forall u\in [1,n]\)我们可以将他的儿子钦定为“+儿子”和“-儿子”,每次把“+儿子”的硬币匹配“-儿子”的空位,即可,问题解决。

    奇环

    ​ 断开奇环上的一条边\((u,v)\)得到一棵树,由于是奇环,所以u,v的奇偶性一致。所以\((u,v)\)这条边对应的操作就是,将两个同层的点,同时加上或者减去一定数量的硬币。那么我们就先计算出断开后的树,缺了多少个空位或者硬币,如果是奇数则无解,否则就平摊给u,v,然后类似树的做法,统计答案即可。

    偶环

    ​ 断开偶环上的一条边\((u,v)\)得到一棵树,由于是偶环,所以u,v的奇偶性不一致。所以,\((u,v)\)这条边对应的操作是,从u将x个硬币移到v上。那么我们记u的系数为1,v的系数为-1,并将子树分类:

    1、系数为1,子树中仅包含u

    2、系数为-1,子树中仅包含v

    3、系数为0,子树中不包含u,v或者同时包含u,v

    那么,答案就是\(ans=\sum_{i=1}^{n}{|k_ix+S_i|}+|x|\)

    这就变成了一个经典问题,取中位数即可。

    Code

    /**************************************************************
        Problem: 3175
        User: ez_hjw
        Language: C++
        Result: Accepted
        Time:61 ms
        Memory:10168 kb
    ****************************************************************/
     
     
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn = 100000 + 10;
     
    inline int rd() {
      int x = 0; char ch = getchar();
      while(ch < '0' || ch > '9') ch = getchar();
      do{
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
      }while(ch >= '0' && ch <= '9');
      return x;
    }
     
    int n, m, cnt, h[maxn], sum = 0, flag, kx[maxn], val[maxn];
     
    struct enode{
      int v, n;
      enode() {}
      enode(int _v, int _n):v(_v), n(_n) {}
    }e[maxn << 1];
     
    inline void addedge(int u, int v) { cnt ++; e[cnt] = enode(v,h[u]); h[u] = cnt; }
     
    int dep[maxn], vis[maxn], Sx, Tx, st[maxn];
    void dfs(int u, int fa) {
      dep[u] = dep[fa] ^ 1;
      vis[u] = 1;
      for(int i = h[u];~ i;i = e[i].n) {
        int v = e[i].v;
        if(v == fa) continue;
        if(vis[v]) Sx = u, Tx = v, flag = (dep[u] == dep[v]);
        else dfs(v,u);
      }
    }
     
    void solve(int u, int fa) {
      for(int i = h[u];~ i;i = e[i].n) {
        int v = e[i].v;
        if(v == fa) continue;
        if((u == Sx && v == Tx) || (u == Tx && v == Sx)) continue;
        solve(v,u);
        val[u] += val[v];
        kx[u] += kx[v];
        }
    }
     
    int main() {
      n = rd(); m = rd();
      cnt = 0;
      memset(h,-1,sizeof(h));
      for(int i = 1;i <= m;i ++) {
        int u, v;
        u = rd(); v = rd();
        addedge(u,v);
        addedge(v,u);
      }
      flag = 0;
      dep[0] = 0;
      dfs(1,0);
      int ans = 0;
      for(int i = 1;i <= n;i ++) {
        if(dep[i]) val[i] = 1;
        else val[i] = -1;
        sum += val[i];
      }
      if(m == n - 1) {
        if(sum) {
          puts("-1");
          return 0;
          }
      }
      else {
        if(flag) {
          if(sum & 1) {
            puts("-1");
            return 0;
            }
            val[Sx] -= sum / 2;
            val[Tx] -= sum / 2;
            ans += abs(sum) / 2;
          }
          else {
            if(sum) {
              puts("-1");
              return 0;
            }
            kx[Sx] = 1;
            kx[Tx] = -1;
        }
      }
      solve(1,0);
      int top;
      st[top = 1] = 0;
      for(int i = 1;i <= n;i ++) {
        if(!kx[i]) ans += abs(val[i]);
        else st[++ top] = - val[i];
        }
        sort(st + 1,st + top + 1);
        int k = st[(top + 1) >> 1];
        for(int i = 1;i <= top;i ++) {
          ans += abs(st[i] - k);
        }
        printf("%d\n", ans);
      return 0;
    }
    

    居然上榜了

  • 相关阅读:
    request.getRealPath的替代方法
    springmvc文件上传示例
    查询表部分列
    表名作为变量的应用
    行转列
    老男孩python学习第三天作业
    老男孩python学习第四天作业
    老男孩python学习第二天思维导图
    老男孩python学习第三天思维导图
    老男孩python学习第五天思维导图
  • 原文地址:https://www.cnblogs.com/ezhjw/p/9508079.html
Copyright © 2011-2022 走看看