码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】HDU5824 graph

时间:2020-06-16 13:29:03      阅读:73      评论:0      收藏:0      [点我收藏+]

标签:http   efi   copy   open   std   --   def   cstring   size   

题意

链接

\(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 \times 10^4, k \le 20, T \le 5 \times 10^5\)

做法

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

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

改变求和的顺序,第二个求和号本质就是在图中有序地选出 \(k\) 棵树的方案数,因此可以强制要求有序\(k\) 颗树,其他的的任意,而每个图被这样统计的次数是 \(\binom{f(G)}{i}\),和原来的式子相同,求和即可。

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

\(T_k = G \times 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(‘\n‘);
  return 0;
}

【题解】HDU5824 graph

标签:http   efi   copy   open   std   --   def   cstring   size   

原文地址:https://www.cnblogs.com/RiverHamster/p/sol-hdu5824.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!