BZOJ 3456 城市规划( NTT + 多项式求逆 )

it2022-05-05  175

题目链接:

https://www.lydsy.com/JudgeOnline/problem.php?id=3456

题意:

求出\(n\)个点的简单(无重边无自环)无向连通图的个数。(\(n<=130000\)).

并且输出方案数mod \(1004535809(479 * 2 ^ {21} + 1)\).

题解:

这题是POJ 1737的加强版。

从之前写过的题解中:

POJ 1737 Connected Graph

我们知道存在这样的递推式:

\[f[n]=2^{C(n,2)}-\sum_{i=1}^{n-1}f[i]*C(n-1,i-1)*2^{C(n-i,2)}\]

将上式左右两边同除以\((n−1)!\)得到:

\[\frac{f[n]}{(n−1)!}=\frac{2^{C(n,2)}}{(n−1)!} - \frac{\sum_{i=1}^{n-1}f[i]*C(n-1,i-1)*2^{C(n-i,2)}}{(n−1)!}\]

\[\implies \frac{f[n]}{(n−1)!}=\frac{2^{C(n,2)}}{(n−1)!} - \sum_{i=1}^{n-1}\frac{f[i]*2^{C(n-i,2)}}{(i-1)!*(n-i)!}\]

\[\implies \frac{2^{C(n,2)}}{(n−1)!}=\sum_{i=1}^{n}\frac{f[i]*2^{C(n-i,2)}}{(i-1)!*(n-i)!} \]

\[\implies \sum_{i=1}^{n}\frac{f[i]}{(i-1)!}*\frac{2^{C(n-i,2)}}{(n-i)!} = \frac{2^{C(n,2)}}{(n−1)!} \]

这个显然是一个卷积的形式。

指数级生成函数。

那么我们可以令:

\[A = \sum_{i=1}^{n}\frac{f[i]}{(i-1)!}x^i\]

\[B = \sum_{i=0}^{n}\frac{2^{C(i,2)}}{i!}x^i\]

\[C = \sum_{i=1}^{n}\frac{2^{C(i,2)}}{(i−1)!}x^i\]

有:

\[A*B = C\]

那么有:

\[A≡C*B^{-1}(mod\ x^{n+1})\]

先预处理\(B\)\(C\),再用多项式求逆得到\(B\)的逆,再跑个NTT就可以了。

复杂度:\(O(nlogn)\).

代码:

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const int maxLen = 18, maxm = 1 << maxLen | 1; const ll maxv = 1e10 + 6; // 1e14, 1e15 const int N = 1000000; const long double pi = acos(-1.0); // double maybe is not enough ll mod = 1004535809, nlim, sp, msk; ll qpower(ll x, ll p) { // x ^ p % mod ll ret = 1; while (p) { if (p & 1) (ret *= x) %=mod; (x *= x) %=mod; p >>= 1; } return ret; } int R[N]; int G = 3; void NTT(int *a,int f,int n,int L) { for(int i = 0;i < n; i++) { R[i] = (R[i>>1]>>1)|((i&1)<<(L-1)); } for(int i = 0;i < n;i++) { if(i < R[i]) swap(a[i],a[R[i]]); } for(int i = 1;i < n;i <<= 1) { int wn = qpower(G,(mod-1)/(i<<1)); if(f==-1) wn = qpower(wn,mod-2); for(int j = 0;j < n;j += (i<<1)) { int w=1; for(int k = 0; k < i; k++,w = 1LL * w * wn % mod) { int x=a[j+k]; int y=1LL*a[j+k+i]*w%mod; a[j+k]=(x+y)%mod; a[j+k+i]=(x-y+mod)%mod; } } } if(f==-1){ int tmp = qpower(n,mod-2); for(int i = 0;i < n;i++) { a[i] = 1LL * a[i] * tmp % mod; } } } int d[N]; void ployInv(int *a,int *b,int n,int L){ if(n == 1){ b[0] = qpower(a[0],mod - 2);return; } ployInv(a,b,n >> 1,L - 1); memcpy(d,a,n*sizeof(int)); memset(d + n,0,n*sizeof(int)); NTT(d,1,n << 1,L + 1); NTT(b,1,n << 1,L + 1); for(int i = 0;i < (n<<1); i++) { b[i] = 1LL * b[i] * ((2LL - 1LL * d[i] * b[i] % mod + mod) % mod) % mod; } NTT(b,-1,n << 1,L + 1); memset(b + n,0,n * sizeof(int)); } ll n,m; ll fac[N]; int L; int A[N],B[N],C[N],inv_B[N]; int main() { // freopen("in.txt","r",stdin); std::cin >> n; m = 1; while(m <= (n << 1)) m<<=1, L++; fac[0] = 1; for(int i = 1; i <= n; i++) { fac[i] = fac[i-1] * i % mod; } for(ll i = 0; i <= n; i++) { B[i] = qpower(2,(i * (i - 1)>>1)) * qpower(fac[i],mod - 2) % mod; } for(ll i = 1; i <= n; i++) { C[i] = qpower(2,(i * (i - 1)>>1)) * qpower(fac[i - 1],mod - 2) % mod; } A[0] = 1; ployInv(B,inv_B,m,L); NTT(inv_B,1,m,L); NTT(C,1,m,L); for(int i = 0; i < m; i++) { A[i] = 1LL * inv_B[i] * C[i] % mod; } NTT(A,-1,m,L); std::cout << A[n] * fac[n-1] % mod << '\n'; return 0; }

转载于:https://www.cnblogs.com/LzyRapx/p/9114391.html

相关资源:各显卡算力对照表!

最新回复(0)