• 【题解】HDU5824 graph


    题意

    链接

    (G(n))(n) 个点的无向简单图的集合,(f(G))(G) 的所有极大连通块中树的个数。

    [sum_{G(n)} f^k(G) ]

    • (n le 10^4, k le 20, T le 100)
    • (n le 5 imes 10^4, k le 20, T le 5 imes 10^5)(T) 为数据组数。

    做法

    首先考虑将 (k) 次幂拆成下降幂的形式:

    [sum_{g in G(n)} sum_{i=1}^{f(g)} f^{underline{i}}(g) cdot egin{Bmatrix} k \ i end{Bmatrix} ]

    改变求和的顺序

    [sum_{i=1}^k egin{Bmatrix} k \ i end{Bmatrix} sum_{g in G(n)} f^{underline i}(g) ]

    第二个求和号的组合意义就是在每个图中有序地选出 (k) 棵树的方案数,继续改变求和顺序,转为有序枚举 (k) 棵树,然后计算包含它们的图的总数。

    (G)(n) 点无向图的 EGF,(T)(n) 点树的 EGF,因为要求 一定选出 (k) 颗树,所以这里 (T_0 = 0)

    (T_k = G imes T^k) 为强制选出选出 (k) 颗树的 EGF,带回原式乘上 Stirling 数的值即可。

    (T_k) 的复杂度:(mathcal O(kn log n))

    带回求答案的复杂度:(mathcal O(k^2 cdot n))

    Code

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
    typedef long long ll;
    namespace io {
      const int SIZE = (1 << 21) + 1;
      char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
      #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
      char getc () {return gc();}
      inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
      inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
      template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
      template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr --]);}
      struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
    }
    using io :: gi; using io :: putc; using io :: print; using io :: getc;
    template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
    template<class T> void upmin(T &x, T y){x = x<y ? x : y;}
    const int p = 998244353;
    inline int add(int x, int y) { return x + y >= p ? x + y - p : x + y; }
    inline int sub(int x, int y) { return x - y < 0 ? x - y + p : x - y; }
    inline int mul(int x, int y) { return 1LL * x * y % p; }
    inline void inc(int &x, int y=1) {x += y; if (x >= p) x -= p;}
    inline void dec(int &x, int y=1) {x -= y; if(x < 0) x += p;}
    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, p - 2); }
    
    const int N = 262144, L = 262144, K = 22;
    const int g = 3, ig = inv(g);
    
    int Ni[N], Ki[N];
    int n = 0, k = 0;
    int f[K][N];
    int W[L], iW[L];
    int rev[L], last = 0;
    int fac[N], ifac[N];
    int S[K][K];
    
    void prework(){
      W[0] = iW[0] = 1;
      W[1] = power(g, (p - 1) / L); iW[1] = inv(W[1]);
      for(int i=2; i<(L>>1); i++){
        W[i] = mul(W[i - 1], W[1]);
        iW[i] = mul(iW[i - 1], iW[1]);
      }
    
      fac[0] = 1;
      for(int i=1; i<=n; i++) fac[i] = mul(fac[i - 1], i);
      ifac[n] = inv(fac[n]);
      for(int i=n-1; i>=0; i--) ifac[i] = mul(ifac[i + 1], i + 1);
    
      S[0][0] = 1;
      for(int i=1; i<=20; i++)
        for(int j=1; j<=i; j++)
          S[i][j] = add(S[i - 1][j - 1], mul(j, S[i - 1][j]));
    }
    
    void init(int n){
      if(last == n) return ;
      last = n;
      int lg = __builtin_ctz(n) - 1;
      for(int i=1; i<n; i++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg);
    }
    void NTT(int a[], int n, int w[]){
      init(n);
      for(int i=0; i<n; i++)
        if(i < rev[i]) swap(a[i], a[rev[i]]);
      for(int l=2, k=1; l<=n; l<<=1, k<<=1){
        int wi = L / l;
        for(int i=0; i<n; i+=l)
          for(int j=i, li=i+k, wp=0; j<li; j++, wp+=wi){
            int x = a[j], y = mul(a[j + k], w[wp]);
            a[j] = add(x, y); a[j + k] = sub(x, y);
          }
      }
    }
    
    void work(){
      prework();
      static int T[L];
      static int Tk[K][L];
    
      int len = 1;
      for(; len < n * 2 + 2; len <<= 1) ;
      T[0] = 0; T[1] = 1;
      Tk[0][0] = 1; Tk[0][1] = 1;
      for(int i=2; i<=n; i++){
        Tk[0][i] = mul(power(2, ((1LL * i * (i - 1)) >> 1) % (p - 1)), ifac[i]);
        T[i] = mul(power(i, i - 2), ifac[i]);
      }
    
      int invlen = inv(len);
      NTT(T, len, W);
      static int tp[L];
      for(int i=1; i<=k; i++){
        copy_n(Tk[i - 1], len, tp);
        NTT(tp, len, W);
        for(int j=0; j<len; j++)
          Tk[i][j] = mul(tp[j], T[j]);
        NTT(Tk[i], len, iW);
        for(int j=0; j<=n; j++)
          Tk[i][j] = mul(Tk[i][j], invlen);
        fill(Tk[i] + n + 1, Tk[i] + len, 0);
      }
      for(int i=1; i<=k; i++)
        for(int j=1; j<=n; j++)
          Tk[i][j] = mul(Tk[i][j], fac[j]);
      
      for(int i=1; i<=k; i++)
        for(int j=1; j<=i; j++)
          for(int p=1; p<=n; p++)
            inc(f[i][p], mul(Tk[j][p], S[i][j]));
    }
    
    int main(){
      File("xuanyiming");
      int T;
      gi(T);
      for(int i=0; i<T; i++){
        gi(Ni[i]); gi(Ki[i]);
        upmax(n, Ni[i]); upmax(k, Ki[i]);
      }
    
      work();
    
      for(int i=0; i<T; i++)
        print(f[Ki[i]][Ni[i]]), putc('
    ');
      return 0;
    }
    
  • 相关阅读:
    优酷网的架构学习笔记
    同网关劫持与不同网关劫持实例
    .flv和.swf格式文件flash播放器代码
    让IE6显示透明PNG背景图片
    新手买车的九大原则
    服务器不支持FLV视频播放的原因
    功能强大易用的Web视频播放器——Flowplayer(使用方法及演示)
    一个不错的媒体网页播放器(国外的)
    网页表格中单元格线条及边框的设置
    20多个漂亮的使用jQuery交互的网站设计欣赏
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-hdu5824.html
Copyright © 2020-2023  润新知