有标号的二分图计数 [生成函数 多项式]
2017-05-03 20:36
253 查看
有标号的二分图计数
题目也在COGS上[HZOI 2015]有标号的二分图计数 I
[HZOI 2015]有标号的二分图计数 II
[HZOI 2015]有标号的二分图计数 III
I
求n个点的二分图(可以不连通)的个数。\(n \le 10^5\)
其中二分图进行了黑白染色,两个二分图不同:边不同 或 点的颜色不同
水题啊,只有黑白之间连边。
\[
\sum_{k=0}^n \binom{n}{k} 2^{k(n-k)}
\]
II
求n个点的二分图(可以不连通)的个数。\(n \le 10^5\)
不能简单的除以2,问题在于有的黑白之间不连边
i个连通块,贡献就是\(2^i\)
DP \(f(n,i)\)表示n个点i个连通块的二分图个数,\(O(n^3)\)
考虑生成函数!
\(S(x)\)表示上道题,\(F(x)\)表示本题
还是不好做,因为都与连通块有关,引入\(H(x)\)表示单个连通块!
\[
S(x) = \sum_{i \ge 0} \frac{2^i \cdot H(x)^i}{i!} \\
F(x) = \sum_{i \ge 0} \frac{H(x)^i}{i!} = \sqrt{S(x)}\\
\]
多项式开根即可
III
求n个点的二分图(必须连通)的个数。\(n \le 10^5\)
就是\(H(x)\)
就是\(\frac{1}{2} \ln S(x)\)
Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N = 1e5+5, P = 998244353; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } ll Pow(ll a, int b) { ll ans = 1; for(; b; b>>=1, a=a*a%P) if(b&1) ans=ans*a%P; return ans; } int n; ll inv , fac , facInv ; inline ll C(int n, int m) {return fac * facInv[m] %P * facInv[n-m] %P;} int main() { freopen("QAQ_bipartite_one.in", "r", stdin); freopen("QAQ_bipartite_one.out", "w", stdout); //freopen("in", "r", stdin); n = read(); inv[1] = fac[0] = facInv[0] = 1; for(int i=1; i<=n; i++) { if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P; fac[i] = fac[i-1] * i %P; facInv[i] = facInv[i-1] * inv[i] %P; } ll ans = 0; for(int k=0; k<=n; k++) ans = (ans + C(n, k) * Pow(2, (ll) k * (n-k) % (P-1))) %P; printf("%lld\n", ans); }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N = (1<<18) + 5, P = 998244353, qr2 = 116195171, inv2 = (P+1)/2; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } ll Pow(ll a, int b) { ll ans = 1; for(; b; b >>= 1, a = a * a %P) if(b & 1) ans = ans * a %P; return ans; } namespace fft { int rev ; void dft(int *a, int n, int flag) { int k = 0; while((1<<k) < n) k++; for(int i=0; i<n; i++) { rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1)); if(i < rev[i]) swap(a[i], a[rev[i]]); } for(int l=2; l<=n; l<<=1) { int m = l>>1; ll wn = Pow(3, flag == 1 ? (P-1)/l : P-1-(P-1)/l); for(int *p = a; p != a+n; p += l) for(int k=0, w=1; k<m; k++, w = w*wn%P) { int t = (ll) w * p[k+m] %P; p[k+m] = (p[k] - t + P) %P; p[k] = (p[k] + t) %P; } } if(flag == -1) { ll inv = Pow(n, P-2); for(int i=0; i<n; i++) a[i] = a[i] * inv %P; } } void sqr(int *a, int n) { dft(a, n, 1); for(int i=0; i<n; i++) a[i] = (ll) a[i] * a[i] %P; dft(a, n, -1); } void inverse(int *a, int *b, int l) { static int t ; if(l == 1) {b[0] = Pow(a[0], P-2); return;} inverse(a, b, l>>1); int n = l<<1; for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0; dft(t, n, 1); dft(b, n, 1); for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P; dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0; } void sqrt(int *a, int *b, int l) { static int t , ib ; if(l == 1) {b[0] = 1; return;} sqrt(a, b, l>>1); int n = l<<1; for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = ib[i] = ib[i+l] = 0; inverse(b, ib, l); dft(t, n, 1); dft(b, n, 1); dft(ib, n, 1); for(int i=0; i<n; i++) b[i] = (ll) inv2 * (b[i] + (ll) t[i] * ib[i] %P) %P; dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0; } } int n, a , f , len; ll inv , fac , facInv , mi ; int main() { //freopen("in", "r", stdin); freopen("QAQ_bipartite_two.in", "r", stdin); freopen("QAQ_bipartite_two.out", "w", stdout); n = read(); len = 1; while(len <= n) len <<= 1; inv[1] = fac[0] = facInv[0] = 1; for(int i=1; i<=n; i++) { if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P; fac[i] = fac[i-1] * i %P; facInv[i] = facInv[i-1] * inv[i] %P; } for(int i=0; i<=n; i++) a[i] = facInv[i] * Pow(Pow(qr2, (ll) i * i %(P-1) ), P-2) %P; fft::sqr(a, len<<1); for(int i=0; i<=n; i++) a[i] = a[i] * Pow(qr2, (ll) i * i %(P-1)) %P; fft::sqrt(a, f, len); printf("%lld\n", (ll) f * fac %P); }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N = (1<<18) + 5, P = 998244353, qr2 = 116195171, inv2 = (P+1)/2; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } ll Pow(ll a, int b) { ll ans = 1; for(; b; b >>= 1, a = a * a %P) if(b & 1) ans = ans * a %P; return ans; } ll inv , fac , facInv ; namespace fft { int rev ; void dft(int *a, int n, int flag) { int k = 0; while((1<<k) < n) k++; for(int i=0; i<n; i++) { rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1)); if(i < rev[i]) swap(a[i], a[rev[i]]); } for(int l=2; l<=n; l<<=1) { int m = l>>1; ll wn = Pow(3, flag == 1 ? (P-1)/l : P-1-(P-1)/l); for(int *p = a; p != a+n; p += l) for(int k=0, w=1; k<m; k++, w = w*wn%P) { int t = (ll) w * p[k+m] %P; p[k+m] = (p[k] - t + P) %P; p[k] = (p[k] + t) %P; } } if(flag == -1) { ll inv = Pow(n, P-2); for(int i=0; i<n; i++) a[i] = a[i] * inv %P; } } void sqr(int *a, int n) { dft(a, n, 1); for(int i=0; i<n; i++) a[i] = (ll) a[i] * a[i] %P; dft(a, n, -1); } void inverse(int *a, int *b, int l) { static int t ; if(l == 1) {b[0] = Pow(a[0], P-2); return;} inverse(a, b, l>>1); int n = l<<1; for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0; dft(t, n, 1); dft(b, n, 1); for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P; dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0; } void ln(int *a, int *b, int l) { static int da , ia ; int n = l<<1; for(int i=0; i<n; i++) da[i] = ia[i] = 0; for(int i=0; i<l-1; i++) da[i] = (ll) (i+1) * a[i+1] %P; inverse(a, ia, l); dft(da, n, 1); dft(ia, n, 1); for(int i=0; i<n; i++) b[i] = (ll) da[i] * ia[i] %P; dft(b, n, -1); for(int i=l-1; i>0; i--) b[i] = (ll) inv[i] * b[i-1] %P; b[0] = 0; for(int i=l; i<n; i++) b[i] = 0; } } int n, a , f , len; int main() { //freopen("in", "r", stdin); freopen("QAQ_bipartite_thr.in", "r", stdin); freopen("QAQ_bipartite_thr.out", "w", stdout); n = read(); len = 1; while(len <= n) len <<= 1; inv[1] = fac[0] = facInv[0] = 1; for(int i=1; i<=len; i++) { if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P; fac[i] = fac[i-1] * i %P; facInv[i] = facInv[i-1] * inv[i] %P; } for(int i=0; i<=n; i++) a[i] = facInv[i] * Pow(Pow(qr2, (ll) i * i %(P-1) ), P-2) %P; fft::sqr(a, len<<1); for(int i=0; i<=n; i++) a[i] = a[i] * Pow(qr2, (ll) i * i %(P-1)) %P; fft::ln(a, f, len); printf("%lld\n", f * fac %P * inv2 %P); }
相关文章推荐
- [多项式] COGS 有标号的二分图计数系列
- [带标号DAG计数 容斥原理 多项式求逆 多项式求ln] COGS 有标号的DAG计数系列
- [带标号无向连通图计数 容斥原理 多项式求逆 多项式求ln 模板题] BZOJ 3456 城市规划
- COGS 有标号的二分图计数系列
- [多项式ln][多项式exp][多项式求幂][生成函数][DP][FNT] BZOJ 3684: 大朋友和多叉树
- hdu 4609 3-idiots [fft 生成函数 计数]
- 有标号DAG计数 [容斥原理 子集反演 组合数学 fft]
- BZOJ 3456 城市规划 NTT 生成函数计数 ***
- HDU 4609 3-idiots(多项式计数 + FFT卷积优化)
- [多项式ln][多项式exp][背包DP][生成函数] LOJ #556. 咱们去烧菜吧
- BZOJ4818 [SDOI2017]序列计数 【生成函数 + 快速幂】
- BZOJ 4001 TJOI 2015 概率论 卡特兰数 生成函数计数
- hdu5729 Rigid Frameworks(连通二分图计数dp)
- [HDU 5729] Rigid Frameworks (二分图联通方案计数)
- [bzoj3625][Codeforces 250 E]The Child and Binary Tree(生成函数+多项式运算+FFT)
- bzoj3456 城市规划【生成函数+多项式求逆元】
- BZOJ 3625: [Codeforces Round #250]小朋友和二叉树 dp 生成函数 多项式开根
- [BZOJ3456]城市规划(生成函数+多项式求逆+多项式求ln)
- 无标号生成树计数
- HDU 5622 KK's Chemical(dp + 计数、特殊图的染色多项式)