luogu P3349 [ZJOI2016]小星星
发现要求的一一映射的条件可以转化为,图中的每个点至少被树上的点映射了一次。考虑对此进行容斥,每次限定一个集合内的数不可被映射,最后乘上容斥系数。
设 f[x][i] 表示树上 x 被映射到 i 的方案数,则转移为:
f[x][i]=∏v∈son∑j∈Smap[i][j]×f[v][j]
其中 S 表示没有被限制的集合, map 的图的邻接矩阵。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define int long long
using namespace std;
const int N = 20;
int n, m, head[N], cnt, map[N][N], f[N][N];
struct Edge
{
int nxt, to;
}g[N * N];
void add(int from, int to)
{
g[++cnt].nxt = head[from];
g[cnt].to = to;
head[from] = cnt;
}
void init()
{
scanf("%lld %lld", &n, &m);
for (int i = 1, x, y; i <= m; i++)
scanf("%lld %lld", &x, &y), map[x][y] = map[y][x] = 1;
for (int i = 1, x, y; i < n; i++)
scanf("%lld %lld", &x, &y), add(x, y), add(y, x);
}
void calc(int x, int fa, int S)
{
for (int i = 1; i <= n; i++)
if ((S & (1 << i - 1)) == 0)
f[x][i] = 1;
else
f[x][i] = 0;
for (int i = head[x]; i; i = g[i].nxt)
{
int v = g[i].to;
if (v == fa) continue;
calc(v, x, S);
for (int j = 1; j <= n; j++)
{
if ((S & (1 << j - 1))) continue;
int tmp = 0;
for (int k = 1; k <= n; k++)
{
if ((S & (1 << k - 1)) || !map[j][k]) continue;
tmp += f[v][k];
}
f[x][j] *= tmp;
}
}
}
void work()
{
int ans = 0, MaxN = 1 << n;
for (int i = 0; i < MaxN; i++)
{
calc(1, -1, i);
int sum = 0, tmp = 0;
for (int j = 1; j <= n; j++)
if ((i & (1 << j - 1))) tmp++;
else sum += f[1][j];
tmp = (tmp & 1) ? -1 : 1;
ans = (ans + tmp * sum);
}
printf("%lld\n", ans);
}
signed main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)