【BZOJ 4455】【UOJ #185】【ZJOI 2016】小星星

http://www.lydsy.com/JudgeOnline/problem.php?id=4455

http://uoj.ac/problem/185

有一个$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;
}
posted @ 2016-08-16 21:13  abclzr  阅读(359)  评论(0编辑  收藏  举报