UOJ #37. [清华集训 2014] 主旋律
考虑 dp。设 为点集 构成强连通分量的方案数。
容易想到容斥。设 为 内部连边数,那么 就是总的方案数 减去构成的不是强连通分量的方案数。
我们考虑如果整个图不是一个强连通分量,那么缩点后一定有 个分量,并且缩完点后图变成一个 DAG。
由此我们想到钦定 为点集 是入度为 的所有强连通分量点集的并集(注意这里 可以 ,因为可以有 个入度为 的强连通分量)。
但是这样会有算重,因为我们无法保证 中的分量就一定是全部入度为 的强连通分量。考虑容斥,容斥系数为 ,其中 为强连通分量个数,表示选奇数个强连通分量的系数为 ,偶数个为 。
设 为 中分成奇数个分量的方案数减去分成偶数个分量的方案数。容易转移:。注意这里我们钦定 包含 的最低位。
那么 就能转移了。设 为边 的数量,其中 ,那么这个东西可以递推求出。我们要限制其他点不能向 中的点连边,那么 。
code
// Problem: #37. 【清华集训2014】主旋律 // Contest: UOJ // URL: https://uoj.ac/problem/37 // Memory Limit: 256 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define lowbit(x) ((x) & (-(x))) #define pb emplace_back #define fst first #define scd second #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 220; const int maxm = (1 << 15) + 50; const ll mod = 1000000007; ll n, m, in[maxn], pw[maxn], f[maxm], g[maxm], h[maxm], ed[maxm], lg[maxm]; int stk[maxm], top; pii E[maxn]; void solve() { scanf("%lld%lld", &n, &m); for (int i = 0; i < n; ++i) { lg[1 << i] = i; } pw[0] = 1; for (int i = 1; i < maxn; ++i) { pw[i] = pw[i - 1] * 2 % mod; } for (int i = 1, u, v; i <= m; ++i) { scanf("%d%d", &u, &v); --u; --v; in[v] |= (1 << u); E[i] = make_pair(u, v); } for (int S = 1; S < (1 << n); ++S) { for (int i = 1; i <= m; ++i) { int u = E[i].fst, v = E[i].scd; if ((S & (1 << u)) && (S & (1 << v))) { ++ed[S]; } } } for (int S = 1; S < (1 << n); ++S) { f[S] = pw[ed[S]]; for (int T = S; T; T = (T - 1) & S) { stk[++top] = T; } while (top) { int T = stk[top--]; h[T] = h[T ^ lowbit(T)] + __builtin_popcount(in[lg[lowbit(T)]] & S); } for (int T = (S - 1) & S; T; T = (T - 1) & S) { if (T & lowbit(S)) { g[S] = (g[S] - f[T] * g[S ^ T] % mod + mod) % mod; } } for (int T = S; T; T = (T - 1) & S) { f[S] = (f[S] - pw[ed[S] - h[T]] * g[T] % mod + mod) % mod; } g[S] = (g[S] + f[S]) % mod; } printf("%lld\n", f[(1 << n) - 1]); } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App