WC模拟(12.20) T2 随机二分图(bzoj5006)

来源:互联网 发布:分期贷款软件 编辑:程序博客网 时间:2024/04/30 20:15

随机二分图

题目背景:

12.20 WC模拟T2 (bzoj5006)

分析:记忆化搜索 + hash状态剪枝

 

据说,这个题的20分和100分是一个复杂度······然后自己写写发现是真的·····考虑,怎么做这道题,首先,对于第一种边,直接转移就好了,对于第二种边,我们可以把它看做是每一条50%的概率出现,再加上25%的概率同时出现,对于第三种边,看做是每一条50%的概率出现,再减去25%的概率同时出现。也就是说在全部都为第一种边的基础上,加上或者减去某些可能,因为要乘上2n,相当于每加一条边就乘上2,但是按道理应该是所以说从所有的50%概率转移一条边,* 2就相当于直接加上一份贡献,25%转移两条边,就相当于* 4,也是直接加上一份贡献,所以直接状压f[i][j]表示,当前左边被选择的点的状态为i,右边被选择的点的状态为j,当前的方案数是多少,然后向上述所说转移即可。注意枚举转移时,只用枚举最小的点,否则会算重复,需要用哈希优化状态数,否则存不下。

 

Source:

/*created by scarlyw*/#include <cstdio>#include <string>#include <algorithm>#include <cstring>#include <iostream>#include <cmath>#include <cctype>#include <vector>#include <set>#include <queue>inline char read() {static const int IN_LEN = 1024 * 1024;static char buf[IN_LEN], *s, *t;if (s == t) {t = (s = buf) + fread(buf, 1, IN_LEN, stdin);if (s == t) return -1;}return *s++;}///*template<class T>inline void R(T &x) {static char c;static bool iosig;for (c = read(), iosig = false; !isdigit(c); c = read()) {if (c == -1) return ;if (c == '-') iosig = true;}for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;}//*/const int OUT_LEN = 1024 * 1024;char obuf[OUT_LEN], *oh = obuf;inline void write_char(char c) {if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;*oh++ = c;}template<class T>inline void W(T x) {static int buf[30], cnt;if (x == 0) write_char('0');else {if (x < 0) write_char('-'), x = -x;for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;while (cnt) write_char(buf[cnt--]);}}inline void flush() {fwrite(obuf, 1, oh - obuf, stdout);}/*template<class T>inline void R(T &x) {static char c;static bool iosig;for (c = getchar(), iosig = false; !isdigit(c); c = getchar())if (c == '-') iosig = true;for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;}//*/const int hash_mod = 10000000 + 19;const int mod = 1000000000 + 7;const int MAXN = 20;int type[MAXN][MAXN], next[MAXN][MAXN];int n, m, t, x, y, a, b;struct node {int a, b, f;node() {}node(int a = 0, int b = 0, int f = 0) : a(a), b(b), f(f) {}} ;std::vector<node> hash[hash_mod];inline int hash_val(int a, int b) {return (a << n | b) % hash_mod;}inline void add(int &x, int t) {x += t, (x >= mod) ? (x -= mod) : (0);}inline void read_in() {memset(type, -1, sizeof(type));R(n), R(m);for (int i = 1; i <= m; ++i) {R(t);if (t == 0) R(x), R(y), x--, y--, type[x][y] = 0; else {R(x), R(y), R(a), R(b), x--, y--, a--, b--;type[x][y] = type[a][b] = t;next[x][y] = a * MAXN + b, next[a][b] = x * MAXN + y;}}hash[0].push_back(node(0, 0, 1));}inline int dfs(int a, int b) {int mask = hash_val(a, b);for (int p = 0; p < hash[mask].size(); ++p) {node *cur = &hash[mask][p];if (cur->a == a && cur->b == b) return cur->f;}int ret = 0;for (int i = 0; i < n; ++i)if ((1 << i) & a) {for (int j = 0; j < n; ++j)if ((1 << j) & b) {switch (type[i][j]) {case 0: add(ret, dfs(a ^ (1 << i), b ^ (1 << j)));break ;case 1: {int sta = a ^ (1 << i), stb = b ^ (1 << j);add(ret, dfs(sta, stb));int u = next[i][j] / MAXN, v = next[i][j] % MAXN;if (u != i && v != j && (a & (1 << u)) && (b & (1 << v)))add(ret, dfs(sta ^ (1 << u), stb ^ (1 << v)));break ;}                                                             ca se 2: {int sta = a ^ (1 << i), stb = b ^ (1 << j);add(ret, dfs(sta, stb));int u = next[i][j] / MAXN, v = next[i][j] % MAXN;if (u != i && v != j && (a & (1 << u)) && (b & (1 << v)))add(ret, mod - dfs(sta ^ (1 << u), stb ^ (1 << v)));break ;}}}return hash[mask].push_back(node(a, b, ret)), ret;}}int main() {read_in();printf("%d", dfs((1 << n) - 1, (1 << n) - 1));return 0;}