您的位置:首页 > 其它

uoj185 [ZJOI2016]小星星 【dp + 容斥】

2018-05-16 10:35 411 查看

题目链接

uoj185

题解

设\(f[i][j]\)表示\(i\)为根的子树,\(i\)号点对应图上\(j\)号点时的方案数
显然这样\(dp\)会使一些节点使用同一个节点,此时总的节点数就不满\(n\)个

我们枚举选的点\(S\),再进行\(dp\)
然后根据选的点数量进行容斥

【BZOJ卡不过QAQ】

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define lbt(x) (x & -x)
using namespace std;
const int maxn = 18,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,m,fa[maxn],S,G[maxn][maxn],g[maxn][maxn];
LL f[maxn][maxn];
void dfs(int u){
LL sum;
for (int i = 1; i <= n; i++)
if ((S & (1 << i - 1))) f[u][i] = 1;
else f[u][i] = 0;
for (int to = 1; to <= n; to++) if (g[u][to] && to != fa[u]){
fa[to] = u; dfs(to);
for (int i = 1; i <= n; i++) if (f[u][i]){
sum = 0;
for (int j = 1; j <= n; j++)
sum += f[to][j] * G[i][j];
f[u][i] *= sum;
}
}
}
int main(){
n = read(); m = read(); int a,b;
REP(i,m){
a = read(); b = read();
G[a][b] = G[b][a] = 1;
}
for (int i = 1; i < n; i++){
a = read(); b = read();
g[a][b] = g[b][a] = 1;
}
int maxv = (1 << n) - 1,cnt;
LL sum,ans = 0;
for (S = 1; S <= maxv; S++){
cnt = 0; for (int i = S; i; i -= lbt(i)) cnt++;
dfs(1); sum = 0;
for (int i = 1; i <= n; i++) sum += f[1][i];
if ((n - cnt) & 1) ans -= sum;
else ans += sum;
}
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: