题解HDU5824 graph

Posted riverhamster

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解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)

做法

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

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

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

(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;
}

以上是关于题解HDU5824 graph的主要内容,如果未能解决你的问题,请参考以下文章

HDU4034Graph

Rikka with Graph hdu 6090

HDU6321 Dynamic Graph Matching状压DP 子集枚举

HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)

2018 Multi-University Training Contest 3 1003 / hdu6321 Problem C. Dynamic Graph Matching 状压dp(示例

hdu 5631 Rikka with Graph(图)