【BZOJ 4455】【UOJ #185】【ZJOI 2016】小星星
http://www.lydsy.com/JudgeOnline/problem.php?id=4455
有一个$O(n^n)$的暴力,放宽限制可以转化成$O(2^n)$的容斥,容斥每一层统计用$O(n^3)$的dp来统计。时间复杂度$O(n^3 2^n)$。
卡常!存图用邻接表!减小非递归函数的使用,尽量写到主函数里!
最后终于卡过了QwQ
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 20; int in() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = (k << 3) + (k << 1) + c - '0'; return k * fh; } ll f[N][N]; bool mp[N][N]; struct node {int nxt, to;} T[N << 1]; int pointT[N], cntT = 0, n, m, fa[N], use[N], usenum; void insT(int u, int v) {T[++cntT] = (node) {pointT[u], v}, pointT[u] = cntT;} void mkfa(int x) { for(int i = pointT[x]; i; i = T[i].nxt) if (T[i].to != fa[x]) { fa[T[i].to] = x; mkfa(T[i].to); } } ll cal(int x, int y) { ll mul = 1, ret; int v; for(int i = pointT[x]; i; i = T[i].nxt) if ((v = T[i].to) != fa[x]) { ret = 0; for(int j = 1; j <= usenum; ++j) if (mp[y][use[j]]) ret += f[v][use[j]]; mul *= ret; } return mul; } void dfs(int x) { for(int i = pointT[x]; i; i = T[i].nxt) if (T[i].to != fa[x]) dfs(T[i].to); for(int i = 1; i <= usenum; ++i) f[x][use[i]] = cal(x, use[i]); } int main() { n = in(); m = in(); int u, v; for(int i = 1; i <= m; ++i) { u = in(); v = in(); mp[u][v] = mp[v][u] = true; } for(int i = 1; i < n; ++i) { u = in(); v = in(); insT(u, v); insT(v, u); } fa[1] = 0; mkfa(1); int tot = (1 << n) - 1, mu = n & 1; ll ret, ans = 0; for(int i = 1; i <= tot; ++i) { usenum = 0; for(int j = 0; j < n; ++j) if ((1 << j) & i) use[++usenum] = j + 1; dfs(1); ret = 0; for(int i = 1; i <= usenum; ++i) ret += f[1][use[i]]; if ((usenum & 1) == mu) ans += ret; else ans -= ret; } printf("%lld\n", ans); return 0; }
NOI 2017 Bless All