洛谷 P6662 [POI 2019] Przedszkole
染色问题。给定 个点 条边无向图,求有多少种给每个点赋点权 的方案,使得 。
Subtask :。
考虑因为最终只会用到最多 种颜色,所以设恰好用了 种颜色,把 种颜色映射到 中,方案数为 ;然后再状压 dp,设 表示已经用了前 种颜色,当前 集合中的点已经染色。转移枚举 的严格超集即可。时间复杂度 。
Subtask :。
实际上这是 ABC294Ex K-Coloring。 考虑一些与边数有关的指数级算法。考虑容斥,钦定 中的 必须满足 。设最后连完 中的边后连通块数为 ,答案即 。对于每个 预处理有多少个边集最后会形成 个连通块,即可 回答单次询问。同时因为 很大要注意实现精细。可以 dfs 枚举每条边是否进入 ,一个简单的剪枝是递归到一条边时 在同一个连通块就立刻退出,因为选和不选的贡献抵消。时间复杂度 。
Subtask :每个连通块是一个环。
这是 ABC307E Distinct Adjacent。每个环相互独立,所以只用考虑一个环,最后方案数乘起来。设 为 个点的环的方案数,转移考虑删掉点 ,如果点 和点 颜色相同那么把它们缩起来,同时点 有 种选颜色的方案;否则点 有 种选颜色的方案,因为点 和点 颜色不同所以可以直接删掉点 。因此有 。这个东西还有通向公式 。时间复杂度 。
code
// Problem: P6662 [POI 2019] Przedszkole // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P6662 // Memory Limit: 128 MB // Time Limit: 1500 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; typedef long double ldb; typedef pair<int, int> pii; const int maxn = 100100; const ll mod = 1000000007; inline ll qpow(ll b, ll p) { ll res = 1; while (p) { if (p & 1) { res = res * b % mod; } b = b * b % mod; p >>= 1; } return res; } ll n, m, q; pii E[maxn]; vector<int> G[maxn]; inline void upd(ll &x, ll y) { ((x += y) >= mod ? x -= mod : 0); } namespace Sub1 { const int maxm = (1 << 15) + 50; ll f[19][maxm], fac[maxn], ifac[maxn]; bool g[maxm]; inline ll C(ll n, ll m) { if (n < m || n < 0 || m < 0) { return 0; } else { ll res = ifac[m]; for (ll i = n - m + 1; i <= n; ++i) { res = res * i % mod; } return res; } } void solve() { for (int S = 1; S < (1 << n); ++S) { g[S] = 1; for (int i = 1; i <= n; ++i) { if (S & (1 << (i - 1))) { for (int j : G[i]) { if (S & (1 << (j - 1))) { g[S] = 0; break; } } } } } f[0][0] = 1; for (int i = 0; i < n; ++i) { for (int S = 0; S < (1 << n); ++S) { if (!f[i][S]) { continue; } for (int T = (S + 1) | S; T < (1 << n); T = (T + 1) | S) { if (g[S ^ T]) { upd(f[i + 1][T], f[i][S]); } } } } fac[0] = 1; for (int i = 1; i <= n; ++i) { fac[i] = fac[i - 1] * i % mod; } ifac[n] = qpow(fac[n], mod - 2); for (int i = n - 1; ~i; --i) { ifac[i] = ifac[i + 1] * (i + 1) % mod; } while (q--) { ll x, ans = 0; scanf("%lld", &x); for (int i = 1; i <= min(n, x); ++i) { ans = (ans + C(x, i) * f[i][(1 << n) - 1]) % mod; } printf("%lld\n", ans); } } } namespace Sub2 { ll f[maxn]; int fa[maxn]; int find(int x) { return fa[x] == x ? x : find(fa[x]); } void dfs(int d, int cnt, int op) { if (d > m) { f[cnt] += op; return; } int x = find(E[d].fst), y = find(E[d].scd); if (x == y) { return; } fa[x] = y; dfs(d + 1, cnt - 1, -op); fa[x] = x; dfs(d + 1, cnt, op); } void solve() { for (int i = 1; i <= n; ++i) { fa[i] = i; } mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count()); for (int i = 1; i <= m; ++i) { if (rnd() & 1) { swap(E[i].fst, E[i].scd); } } dfs(1, n, 1); while (q--) { ll x, ans = 0; scanf("%lld", &x); for (int i = n; i >= max(1LL, n - 60); --i) { ans = (ans + (f[i] + mod) * qpow(x, i)) % mod; } printf("%lld\n", ans); } } } namespace Sub3 { int fa[maxn], sz[maxn]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } inline void merge(int x, int y) { x = find(x); y = find(y); if (x != y) { fa[x] = y; sz[y] += sz[x]; } } inline ll calc(ll n, ll m) { return (qpow(m - 1, n) + ((n & 1) ? mod - (m - 1) : m - 1)) % mod; } void solve() { for (int i = 1; i <= n; ++i) { fa[i] = i; sz[i] = 1; } for (int i = 1; i <= m; ++i) { merge(E[i].fst, E[i].scd); } vector<ll> vc; for (int i = 1; i <= n; ++i) { if (fa[i] == i) { vc.pb(sz[i]); } } while (q--) { ll x; scanf("%lld", &x); ll ans = 1; for (ll y : vc) { ans = ans * calc(y, x) % mod; } printf("%lld\n", ans); } } } void solve() { scanf("%lld%lld%lld", &n, &m, &q); for (int i = 1, u, v; i <= m; ++i) { scanf("%d%d", &u, &v); G[u].pb(v); G[v].pb(u); E[i] = mkp(u, v); } if (n <= 15) { Sub1::solve(); return; } if (m <= 24) { Sub2::solve(); return; } Sub3::solve(); } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】