zoukankan      html  css  js  c++  java
  • LOJ#2027. 「SHOI2016」黑暗前的幻想乡+ #2091. 「ZJOI2016」小星星((FWT or 容斥)+ 其它算法)

    https://loj.ac/problem/2027
    https://loj.ac/submission/831930

    https://loj.ac/problem/2091
    https://loj.ac/submission/831907

    对于T1,发现是要每个颜色恰好选一个。

    对于T2,发现是要每个点恰好对应图中的一个点。

    所以可以直接容斥,枚举(S)表示只能选(S)中的点,求个方案数,容斥系数是((-1)^{全集大小-|S|})

    或者说用FWT理解,在做XXX的过程带个二进制状态表示已选那些,每次做or卷积,这样做(比如T1矩阵树里面怎么搞)当然是不行的。

    但可以在外面在FWT,变成点积就是普通的数了,最后再IFWT回去,你发现和容斥的式子是一样的。

    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 = 1e9 + 7;
    
    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 int N = 20;
    
    int n;
    int m[N], a[N][N * N][2];
    
    ll b[N][N];
    
    ll solve(ll (*a)[N], int n) {
    	ll ans = 1;
    	fo(i, 1, n) {
    		int u = -1;
    		fo(j, i, n) if(a[j][i]) { u = j; break;}
    		if(u == -1) return 0;
    		if(u > i) {
    			ans = -ans;
    			fo(j, i, n) swap(a[i][j], a[u][j]);
    		}
    		ll v = a[i][i];
    		ans = ans * v % mo;
    		v = ksm(v, mo - 2);
    		fo(j, i, n) a[i][j] = a[i][j] * v % mo;
    		fo(j, i + 1, n) if(a[j][i]) {
    			v = -a[j][i];
    			fo(k, i, n) a[j][k] = (a[j][k] + a[i][k] * v) % mo;
    		}
    	}
    	return ans;
    }
    
    int main() {
    	freopen("a.in", "r", stdin);
    	scanf("%d", &n);
    	fo(i, 1, n - 1) {
    		scanf("%d", &m[i]);
    		fo(j, 1, m[i]) scanf("%d %d", &a[i][j][0], &a[i][j][1]);
    	}
    	ll ans = 0;
    	for(int s = 1; s < (1 << (n - 1)); s ++) {
    		fo(i, 1, n) fo(j, 1, n) b[i][j] = 0;
    		int xs = ((n - 1) % 2 ? -1 : 1);
    		fo(i, 1, n - 1) if(s >> (i - 1) & 1) {
    			xs = -xs;
    			fo(j, 1, m[i]) {
    				int x = a[i][j][0], y = a[i][j][1];
    				b[x][x] ++; b[y][y] ++; b[x][y] --; b[y][x] --;
    			}
    		}
    		ans = (ans + solve(b, n - 1) * xs) % mo;
    	}
    	ans = (ans % mo + mo) % mo;
    	pp("%lld
    ", ans);
    }
    
    #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 N = 20;
    
    int n, m, x, y;
    int bz[N][N], bx[N][N];
    
    int fa[N];
    
    int s;
    
    int d[N], d0;
    
    #define ull unsigned long long
    
    ull f[N][N];
    
    void dg(int x) {
    	fo(i ,1, d0) f[x][i] = 1;
    	fo(y, 1, n) if(bz[x][y] && fa[x] != y) {
    		fa[y] = x;
    		dg(y);
    		fo(i, 1, d0) {
    			ull s = 1;
    			fo(j, 1, d0) if(bx[d[i]][d[j]])
    				s += f[y][j];
    			f[x][i] = f[x][i] * s;
    		}
    	}
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	fo(i, 1, m) {
    		scanf("%d %d", &x, &y);
    		bx[x][y] = bx[y][x] = 1;
    	}
    	fo(i, 1, n - 1) {
    		scanf("%d %d", &x, &y);
    		bz[x][y] = bz[y][x] = 1;
    	}
    	ull ans = 0;
    	for(int s = 1; s < (1 << n); s ++) {
    		d0 = 0;
    		ff(j, 0, n) if(s >> j & 1)
    			d[++ d0] = j + 1;
    		int xs = ((n - d0) % 2 ? -1 : 1);
    		dg(1);
    		ll sum = 0;
    		fo(i, 1, d0) sum += f[1][i];
    		if(xs == 1) ans += sum; else ans -= sum;
    	}
    	pp("%llu
    ", ans);
    }
    
  • 相关阅读:
    四则运算测试脚本运行情况
    AAA
    (2015秋) 软工作业成绩公布(12月26号更新)
    判断闰年的Java算法
    B
    A
    Where Amazing Happens
    安利一发资料站
    C
    B
  • 原文地址:https://www.cnblogs.com/coldchair/p/13089043.html
Copyright © 2011-2022 走看看