• CF1408G Clusterization Counting


    题意

    • 给定 (n) 个点的带权无向完全图,点 (i, j) 之间的权值为 (a_{i, j}),权值是一个 (1 sim frac{n(n-1)}{2}) 的排列。
    • 计数把原图划分成 (k) 个组的方案数,满足:
      • 对于任意的 ((s, f), (x, y)),其中 (s, f, x) 同组(y)(x) 不同组(s e f, x e y)),(a_{s, f} < a_{x, y}),即(对于每个组)组间边大于组内边。
    • 输出一行 (n) 个数,对于 (k in [1, n]) 求出答案,对 (998244353) 取模。
    • (n le 1500)

    题解

    考虑从小到大处理边。将边排序,依次在并查集上连接。

    (f_i) 为某个连通块划分成 (i) 个组的方案数。

    如果一个连通块还不是团时就已经和另一个连通块相连接,那么它不能单独成组,因为组内有比组间更大的边(还未加入)。

    初始时每个点可以单独成组,因此对于每个点 (f_1 = 1)。连接两个连通块时直接做多项式卷积即可(不可能发生合并),加入所有边即可得到答案。

    当一个连通块形成一个团时,可以单独成组,因此令 (f_1)(1)

    复杂度 (mathcal O(n^2)),类似树形 DP。

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    using namespace std;
    using ll = long long;
    
    namespace io {
    #define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
      const int SIZE = (1 << 21) + 1;
      char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1;
      inline char getc () {return (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++);}
      inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
      inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
      template<class T>
      inline void read(T &x) {
        char ch; int f = 1;
        x = 0;
        while(isspace(ch = getc()));
        if(ch == '-') ch = getc(), f = -1;
        do x = x * 10 + ch - '0'; while(isdigit(ch = getc()));
        x *= f;
      }
      template<class T, class ...Args>
      inline void read(T &x, Args&... args) {read(x); read(args...);}
      template<class T>
      inline void write(T x) {
        static char stk[128];
        int top = 0;
        if(x == 0) {putc('0'); return;}
        if(x < 0) putc('-'), x = -x;
        while(x) stk[top++] = x % 10, x /= 10;
        while(top) putc(stk[--top] + '0');
      }
      template<class T, class ...Args>
      inline void write(T x, Args... args) {write(x); putc(' '); write(args...);}
      inline void space() {putc(' ');}
      inline void endl() {putc('
    ');}
      struct _flush {~_flush() {flush();}} __flush;
    };
    using io::read; using io::write; using io::flush; using io::space; using io::endl; using io::getc; using io::putc;
    
    const int M = 998244353;
    inline int add(int x, int y) { return x + y >= M ? x + y - M : x + y; }
    template <class... Args> inline int add(int x, int y, Args... args) { return add(add(x, y), args...); }
    inline int sub(int x, int y) { return x - y < 0 ? x - y + M : x - y; }
    inline int mul(int x, int y) { return 1LL * x * y % M; }
    template <class... Args> inline int mul(int x, int y, Args... args) { return mul(mul(x, y), args...); }
    inline void inc(int &x, int y=1) { x += y; if(x >= M) x -= M; }
    inline void dec(int &x, int y=1) { x -= y; if(x < 0) x += M; }
    inline int power(int x, int y) {
      int res = 1;
      for(; y; y>>=1, x = mul(x, x)) if(y & 1) res = mul(res, x);
      return res;
    }
    inline int inv(int x) { return power(x, M - 2); }
    
    using poly = vector<int>;
    poly operator*(poly a, poly b) {
      poly c(a.size() + b.size() + 1);
      for (size_t i = 0; i < a.size(); ++i)
        for (size_t j = 0; j < b.size(); ++j)
          inc(c[i + j + 1], mul(a[i], b[j]));
      return c;
    }
    
    const int N = 1505;
    int fa[N], siz[N], edges[N];
    poly f[N];
    int find(int x) {
      return !fa[x] ? x : fa[x] = find(fa[x]);
    }
    void link(int x, int y) {
      x = find(x), y = find(y);
      if (x == y) {
        ++edges[x];
        if (edges[x] == siz[x] * (siz[x] - 1) / 2)
          ++f[x][0];
        return;
      }
      if (siz[x] < siz[y]) swap(x, y);
      fa[y] = x;
      siz[x] += siz[y];
      edges[x] += edges[y] + 1;
      f[x] = f[x] * f[y];
      if (edges[x] == siz[x] * (siz[x] - 1) / 2)
        ++f[x][0];
    }
    
    struct edge {
      int x, y, w;
    }e[N * N / 2];
    
    int main() {
      File("g");
      int n;
      read(n);
      fill(f + 1, f + 1 + n, poly({1}));
      fill(siz + 1, siz + 1 + n, 1);
      fill(edges + 1, edges + 1 + n, 0);
      int ec = 0;
      for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) {
          int w; read(w);
          if (i < j) e[++ec] = {i, j, w};
        }
      sort(e + 1, e + 1 + ec, [] (edge x, edge y) {return x.w < y.w;});
      for (int i = 1; i <= ec; ++i)
        link(e[i].x, e[i].y);
      int rt = find(1);
      for (int i = 0; i < n; ++i)
        write(f[rt][i]), space();
      endl();
      return 0;
    }
    
  • 相关阅读:
    C++中的回调函数(callback)
    C++ Primer5 练习5.12:编程统计含有两个连续字符(ff、fl、fi)的字符序列的数量
    范围for循环过程中用&修改元素
    C++资料整理(持续更新)
    问题解决:VS报错:The build tools for v140 (Platform Toolset = 'v140') cannot be found
    上传新文件至个人hexo博客的步骤
    【Ubuntu】同时安装了python2和python3,使用pip安装软件时注意
    python解析xml文件 修改xml指定标签中的内容
    实操:main(int argc,char ** argv) 输出main函数的参数
    Saga-Python笔记
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-cf1408g.html
Copyright © 2020-2023  润新知