1. 程式人生 > >[BZOJ2560] 串珠子 [子集列舉][狀態壓縮][dp][容斥]

[BZOJ2560] 串珠子 [子集列舉][狀態壓縮][dp][容斥]

[ L i n k \frak{Link} ]


注意列舉子集計算 F

i \frak{F_i} 的時候要先去掉一個點防止重複計數。
那麼讓能隨意連邊的一邊不包含這個點,不隨意連邊的一邊包含這個點(不能反過來!)


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include
<cmath>
#include<set> #include<ctime> using namespace std; const long long mod = 1000000007; int n; long long c[20][20]; long long F[66666]; long long G[66666]; int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { scanf("%lld", &c[i]
[j]); } } int up = (1 << n) - 1; for (int i = 1; i <= up; ++i) { G[i] = 1; for (int j = 1; j <= n; ++j) { if (!(i & 1 << j - 1)) continue; for (int k = j + 1; k <= n; ++k) { // * from (j+1) if (!(i & 1 << k - 1)) continue; G[i] *= c[j][k] + 1; G[i] %= mod; } } F[i] = G[i]; int upup = i & (i - 1); for (int j = upup; j; j = upup & (j - 1)) { F[i] = (F[i] - G[j] * F[i ^ j] % mod + mod) % mod; } } printf("%lld", F[up]); return 0; }