【ybtoj高效进阶 21285】独立生物(图论)(博弈论)(DP)

独立生物

题目链接:ybtoj高效进阶 21285

题目大意

给你 k 个无向图,和一个点数为 n^k 的无向图 G,G 图中点的表示方式是可以 k 元组。
若设一个 k 元组内所有数的和是 x,G 图中这个点的点权为 V^x。
判定无向图两个点是否有边的方法是:它们转成的 k 元组只有一位不同,而且在那一位对于的图上它们是有边的。

然后要你求图 G 的最大权独立集。
V 很大很大很大。

思路

V 很大的其实其实就是要我们只要能尽可能的让 x 大即可。
(无语)

然后不难有一个贪心的做法,接下来我们考虑怎么搞。
那考虑给边定向,那根据我们的贪心,从点权大的到点权小的。就成了一个 DAG。

而且刚好你会发现是不会出现两个点权相同的点有边。(因为它说了只能有一位不同)
然后你考虑怎么 DP 搞。

会发现根据贪心,如果是在一条链上,就是选一个不选一个这样巴拉巴拉下去。
或者说你可以理解为选了它跟它连边的就不能选了。
DAG 上的这个问题,感觉有点博弈论?

仔细思考会发现,其实你选到的点都是在博弈论上必败的点!

然后 SG 函数在 DAG 转移上的上界是 m,那我们可以暴力搞,直接朴素卷积,也是 O(m) 的。
然后复杂度就是 O(n+m)

代码

#include<map> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define mo 998244353 using namespace std; int n, k, m, x, y, T; ll v, ans[100001], b[100001]; struct graph { struct node { int to, nxt; }e[200001]; int le[100001], KK; int sg[100001], t; ll a[100001]; void start() { memset(sg, -1, sizeof(sg)); } void add(int x, int y) { if (x > y) swap(x, y); e[++KK] = (node){y, le[x]}; le[x] = KK; } int SG(int now) {//博弈论的 SG 函数暴力求 if (sg[now] != -1) return sg[now];//小小记忆化 sg[now] = 0; map <int, bool> G; for (int i = le[now]; i; i = e[i].nxt) G[SG(e[i].to)] = 1; while (G[sg[now]]) sg[now]++; return sg[now]; } void get_SG() { for (int i = n; i >= 1; i--) { sg[i] = SG(i); } } void clac() { ll now = v; for (int i = 1; i <= n; i++) { t = max(t, sg[i]); a[sg[i]] = a[sg[i]] + now; if (a[sg[i]] > mo) a[sg[i]] -= mo; now = now * v % mo; } } }g[6]; int main() { // freopen("biology.in", "r", stdin); // freopen("biology.out", "w", stdout); scanf("%d %d %lld", &n, &k, &v); for (int i = 1; i <= k; i++) { g[i].start(); scanf("%d", &m); for (int j = 1; j <= m; j++) { scanf("%d %d", &x, &y); g[i].add(x, y); } g[i].get_SG(); g[i].clac(); } T = 0; ans[0] = 1; for (int i = 1; i <= k; i++) { for (int j = 0; j <= T; j++) { for (int l = 0; l <= g[i].t; l++) { b[j ^ l] = b[j ^ l] + ans[j] * g[i].a[l] % mo; if (b[j ^ l] > mo) b[j ^ l] -= mo; T = max(T, j ^ l); } } for (int j = 0; j <= T; j++) { swap(ans[j], b[j]); b[j] = 0; } } printf("%lld", ans[0]); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21285.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(35)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示