zoukankan      html  css  js  c++  java
  • Comet Contest#11 F arewell(DAG计数+FWT子集卷积)

    传送门.

    题解:


    4月YY集训时做过DAG计数,和这个基本上是一样的,但是当时好像直接暴力子集卷积,不然我省选时不至于不会,这个就多了个边不选的概率和子集卷积。

    DAG计数是个套路来的,利用的是DAG中入度为0的点。

    (f[S])表示只考虑s里的点的诱导子图形成DAG的方案数。

    枚举一个(T|S~and~T=empty),这个T就是新的图中度数为0的点,首先它们之间要没有边,然后(T)(S)间的边要么没有,要么都由(T->S),记(cnt[S])表示S里的边数,这转移系数是:
    ({1over 3}^{g[T]}*{{2over 3}^{g[S+T]}over {2over 3}^{g[S]+g{T}}})

    注意这样会算重,因为会枚举到度数为0的点的子集,那么容斥系数((-1)^{|T|+1}),考虑用(sum_{i=1}^{|T|}(-1)^{i+1}*C_{|T|}^i=1)来证明。

    直接卷积是(O(3^n)),然后就上or FWT + 1的个数的老套路了,复杂度(O(2^n*n^2))

    Code:


    #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("
    ")
    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
    ", ans);
    } 
    
    
  • 相关阅读:
    第1周作业
    第0次作业
    第三周作业
    随笔1
    第一次作业
    第二周作业
    第零次作业
    第四周作业
    第三周作业
    第二次作业
  • 原文地址:https://www.cnblogs.com/coldchair/p/11575289.html
Copyright © 2011-2022 走看看