傳送門.c++
4月YY集訓時作過DAG計數,和這個基本上是同樣的,可是當時好像直接暴力子集卷積,否則我省選時不至於不會,這個就多了個邊不選的機率和子集卷積。spa
DAG計數是個套路來的,利用的是DAG中入度爲0的點。code
設\(f[S]\)表示只考慮s裏的點的誘導子圖造成DAG的方案數。get
枚舉一個\(T|S~\and~T=\empty\),這個T就是新的圖中度數爲0的點,首先它們之間要沒有邊,而後\(T\)和\(S\)間的邊要麼沒有,要麼都由\(T->S\),記\(cnt[S]\)表示S裏的邊數,這轉移係數是:
\({1\over 3}^{g[T]}*{{2\over 3}^{g[S+T]}\over {2\over 3}^{g[S]+g{T}}}\)it
注意這樣會算重,由於會枚舉到度數爲0的點的子集,那麼容斥係數\((-1)^{|T|+1}\),考慮用\(\sum_{i=1}^{|T|}(-1)^{i+1}*C_{|T|}^i=1\)來證實。class
直接卷積是\(O(3^n)\),而後就上or FWT + 1的個數的老套路了,複雜度\(O(2^n*n^2)\)。test
#include<bits/stdc++.h> #define fo(i, x, y) for(int i = x, B = y; i <= B; i ++) #define ff(i, x, y) for(int i = x, B = y; i < B; i ++) #define fd(i, x, y) for(int i = x, B = y; i >= B; i --) #define ll long long #define pp printf #define hh pp("\n") using namespace std; const int mo = 998244353; ll ksm(ll x, ll y) { ll s = 1; for(; y; y /= 2, x = x * x % mo) if(y & 1) s = s * x % mo; return s; } const ll w1 = ksm(3, mo - 2), w2 = 2 * ksm(3, mo - 2) % mo; const ll nw1 = ksm(w1, mo - 2), nw2 = ksm(w2, mo - 2); const int N = 21; const int M = 1 << 20; int n, m, x, y, a2[N]; int bz[N][N]; ll f[M], nf[M], g[M]; int cnt[M]; void dft(int *a, int n, int f) { for(int h = 1; h < n; h *= 2) for(int j = 0; j < n; j += 2 * h) ff(i, 0, h) { if(f == 1) a[i + j + h] = (a[i + j + h] + a[i + j]) % mo; else a[i + j + h] = (a[i + j + h] - a[i + j]) % mo; } } int a[21][M], b[21][M]; int main() { scanf("%d %d", &n, &m); a2[0] = 1; fo(i, 1, n) a2[i] = a2[i - 1] * 2; fo(i, 1, m) { scanf("%d %d", &x, &y); x --; y --; bz[x][y] = 1; } ff(s, 1, a2[n]) cnt[s] = cnt[s - (s & -s)] + 1; ff(s, 0, a2[n]) { f[s] = g[s] = nf[s] = 1; if(s == 0) continue; int st; ff(i, 0, n) if(s >> i & 1) { st = i;} f[s] = f[s ^ (1 << st)]; g[s] = g[s ^ (1 << st)]; nf[s] = nf[s ^ (1 << st)]; ff(i, 0, st) if(s >> i & 1) { if(bz[st][i]) f[s] = f[s] * w2 % mo, nf[s] = nf[s] * nw2 % mo, g[s] = g[s] * w1 % mo; if(bz[i][st]) f[s] = f[s] * w2 % mo, nf[s] = nf[s] * nw2 % mo, g[s] = g[s] * w1 % mo; } } fo(i, 1, n) { ff(j, 0, a2[n]) if(cnt[j] == i) b[i][j] = nf[j] * g[j] % mo * ((cnt[j] & 1) ? 1 : -1); dft(b[i], a2[n], 1); } a[0][0] = 1; dft(a[0], a2[n], 1); fo(w, 0, n) { fo(j, 1, n - w) { ff(i, 0, a2[n]) a[j + w][i] = ((ll) a[w][i] * b[j][i] + a[j + w][i]) % mo; } } dft(a[n], a2[n], -1); ll ans = a[n][a2[n] - 1]; ans = (ans % mo + mo) * f[a2[n] - 1] % mo; pp("%lld\n", ans); }