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("\n")
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\n", 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("\n")
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\n", ans);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址