zoukankan      html  css  js  c++  java
  • CF917D. Stranger Trees & TopCoder13369. TreeDistance(变元矩阵树定理+高斯消元)

    题目链接

    CF917D:https://codeforces.com/problemset/problem/917/D

    TopCoder13369:https://community.topcoder.com/stat?c=problem_statement&pm=13369

    题解

    首先分析 CF917D。

    我们考虑能否将树上的边的贡献特殊表现出来。

    记原树为 (T),我们构造一幅 (n) 个结点的无向完全图,并设置一个值 (x),对于无向边 ((u, v)),其权值 (w_{(u, v)}) 满足:

    [w_{(u, v)} = egin{cases} x, & (u, v) in T \ 1, & (u, v) otin T end{cases} ]

    如果我们令无向完全图的所有生成树中,恰好有 (i) 条边属于原树 (T) 的生成树数量为 ({ m ans}_i),那么不难发现,根据变元矩阵树定理(基尔霍夫矩阵的任意 (n - 1) 阶主子式的行列式的绝对值即为所有生成树的边权积之和),求得的基尔霍夫矩阵的 (n - 1) 阶主子式的值即为 (sum_limits{i = 0}^{n - 1} x^i { m ans}_i),因为若一个生成树包含了 (i) 条原树边,那么该生成树的边权积即为 (x^i)

    如果我们将 ({ m ans}_i) 视为未知数,那么我们就可以通过枚举 (x: 0 sim n - 1) 来得到一个 (n) 元线性方程组。直接高斯消元即可求得所有的 ({ m ans}_i)

    接下来分析 TopCoder13369。

    考虑原树 (T) 最少能通过多少次操作得到另一棵树 (T'),显然若在原树 (T) 中出现而在树 (T') 中没有出现的边数为 (w),那么只需要 (w) 次操作即可将原树 (T) 变为树 (T')。因此答案即为有 (i(i geq n - 1 - k)) 条边属于原树的生成树数量,即 (sum_limits{i = n - 1 - k}^{n - 1} { m ans}_i)。其余部分与上题相同。

    两题的时间复杂度均为 (O(n^4))

    代码

    CF917D 代码如下:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 105, mod = 1e9 + 7;
    
    void add(int& x, int y) {
      x += y;
      if (x >= mod) {
        x -= mod;
      }
    }
    
    void sub(int& x, int y) {
      x -= y;
      if (x < 0) {
        x += mod;
      }
    }
    
    int mul(int x, int y) {
      return (long long) x * y % mod;
    }
    
    int qpow(int v, int p) {
      int result = 1;
      for (; p; p >>= 1, v = mul(v, v)) {
        if (p & 1) {
          result = mul(result, v);
        }
      }
      return result;
    }
    
    int n, a[N][N], b[N][N];
    bool old[N][N];
    
    int matrix_tree() {
      int result = 1;
      for (int i = 2; i <= n; ++i) {
        int rev = i;
        for (int j = i + 1; j <= n; ++j) {
          if (a[j][i]) {
            rev = j;
            break;
          }
        }
        if (rev != i) {
          result = (mod - result) % mod;
          for (int j = i; j <= n; ++j) {
            swap(a[i][j], a[rev][j]);
          }
        }
        for (int j = i + 1; j <= n; ++j) {
          int p = mul(a[j][i], qpow(a[i][i], mod - 2));
          for (int k = i; k <= n; ++k) {
            sub(a[j][k], mul(p, a[i][k]));
          }
        }
        result = mul(result, a[i][i]);
      }
      return result;
    }
    
    int main() {
      scanf("%d", &n);
      for (int i = 1; i < n; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        old[u][v] = old[v][u] = true;
      }
      for (int x = 0; x < n; ++x) {
        memset(a, 0, sizeof a);
        for (int i = 1; i <= n; ++i) {
          for (int j = 1; j <= n; ++j) {
            int v = old[i][j] ? x : 1;
            add(a[j][j], v);
            sub(a[i][j], v);
          }
        }
        for (int i = 0, v = 1; i < n; ++i, v = mul(v, x)) {
          b[x][i] = v;
        }
        b[x][n] = matrix_tree();
      }
      for (int i = 0; i < n; ++i) {
        int rev = i;
        for (int j = i + 1; j < n; ++j) {
          if (b[j][i]) {
            rev = j;
            break;
          }
        }
        if (rev != i) {
          for (int j = i; j <= n; ++j) {
            swap(b[i][j], b[rev][j]);
          }
        }
        for (int j = i + 1; j < n; ++j) {
          int p = mul(b[j][i], qpow(b[i][i], mod - 2));
          for (int k = i; k <= n; ++k) {
            sub(b[j][k], mul(p, b[i][k]));
          }
        }
      }
      for (int i = n - 1; ~i; --i) {
        for (int j = i + 1; j < n; ++j) {
          sub(b[i][n], mul(b[i][j], b[j][n]));
        }
        b[i][n] = mul(b[i][n], qpow(b[i][i], mod - 2));
      }
      for (int i = 0; i < n; ++i) {
        printf("%d%c", b[i][n], " 
    "[i == n - 1]);
      }
      return 0;
    }
    

    TopCoder13369 代码如下:

    直接粘过来改一下即可。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 55, mod = 1e9 + 7;
    
    void add(int& x, int y) {
      x += y;
      if (x >= mod) {
        x -= mod;
      }
    }
    
    void sub(int& x, int y) {
      x -= y;
      if (x < 0) {
        x += mod;
      }
    }
    
    int mul(int x, int y) {
      return (long long) x * y % mod;
    }
    
    int qpow(int v, int p) {
      int result = 1;
      for (; p; p >>= 1, v = mul(v, v)) {
        if (p & 1) {
          result = mul(result, v);
        }
      }
      return result;
    }
    
    int n, a[N][N], b[N][N];
    bool old[N][N];
    
    int matrix_tree() {
      int result = 1;
      for (int i = 1; i < n; ++i) {
        int rev = i;
        for (int j = i + 1; j < n; ++j) {
          if (a[j][i]) {
            rev = j;
            break;
          }
        }
        if (rev != i) {
          result = (mod - result) % mod;
          for (int j = i; j < n; ++j) {
            swap(a[i][j], a[rev][j]);
          }
        }
        for (int j = i + 1; j < n; ++j) {
          int p = mul(a[j][i], qpow(a[i][i], mod - 2));
          for (int k = i; k < n; ++k) {
            sub(a[j][k], mul(p, a[i][k]));
          }
        }
        result = mul(result, a[i][i]);
      }
      return result;
    }
    
    class TreeDistance {
    public:
      int countTrees(vector<int> p, int c) {
        n = p.size() + 1;
        for (int i = 0; i < p.size(); ++i) {
          old[p[i]][i + 1] = old[i + 1][p[i]] = true;
        }
        for (int x = 0; x < n; ++x) {
          memset(a, 0, sizeof a);
          for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
              int v = old[i][j] ? x : 1;
              add(a[j][j], v);
              sub(a[i][j], v);
            }
          }
          for (int i = 0, v = 1; i < n; ++i, v = mul(v, x)) {
            b[x][i] = v;
          }
          b[x][n] = matrix_tree();
        }
        for (int i = 0; i < n; ++i) {
          int rev = i;
          for (int j = i + 1; j < n; ++j) {
            if (b[j][i]) {
              rev = j;
              break;
            }
          }
          if (rev != i) {
            for (int j = i; j <= n; ++j) {
              swap(b[i][j], b[rev][j]);
            }
          }
          for (int j = i + 1; j < n; ++j) {
            int p = mul(b[j][i], qpow(b[i][i], mod - 2));
            for (int k = i; k <= n; ++k) {
              sub(b[j][k], mul(p, b[i][k]));
            }
          }
        }
        for (int i = n - 1; ~i; --i) {
          for (int j = i + 1; j < n; ++j) {
            sub(b[i][n], mul(b[i][j], b[j][n]));
          }
          b[i][n] = mul(b[i][n], qpow(b[i][i], mod - 2));
        }
        int answer = 0;
        for (int i = n - 1; i >= max(0, n - 1 - c); --i) {
          add(answer, b[i][n]);
        }
        return answer;
      }
    };
    /*
    TreeDistance solver;
    
    int main() {
      int n, k;
      scanf("%d", &n);
      vector<int> p(n - 1);
      for (int i = 0; i < n - 1; ++i) {
        scanf("%d", &p[i]);
      }
      scanf("%d", &k);
      printf("%d
    ", solver.countTrees(p, k));
      return 0;
    }
    */
    
  • 相关阅读:
    亚马逊产品图片爬取
    页面浏览统计之(一) hitcount
    页面浏览统计之(二) tracking
    页面浏览统计之(三) tracking2
    Django CMS apphooks – 使用应用钩子来添加主题应用
    Django CMS 插件 – 添加博客专题
    [整理] Windows下打印网页
    CompletableFuture详解
    详解JVM常量池、Class、运行时、字符串常量池
    分库分表总结
  • 原文地址:https://www.cnblogs.com/ImagineC/p/10156632.html
Copyright © 2011-2022 走看看