题解:P10104 [GDKOI2023 提高组] 异或图

news/2025/10/14 20:26:46/文章来源:https://www.cnblogs.com/LUlululu1616/p/19141947

题意:给定一张 \(n\) 个点 \(m\) 条边的无向图和一个长度为 \(n\) 的数组 \(a_1, a_2, \cdots , a_n\) 以及一个整数 \(C\),你需要求出有多少个长度为 \(n\) 的数组 \(b\) 满足:

  1. \(0 ≤ b_i ≤ a_i,\forall 1 ≤ i ≤ n\)
  2. 对于每条边 \((u, v)\)\(b_u \ne b_v\)
  3. \(b_1 ⊕ b_2 ⊕ \cdots ⊕ b_n = C\),其中 \(\oplus\) 代表异或。

做法:

首先先要会做 \(m=0\),那么我们可以在后面加一个元素 \(a_{n+1}=C\) 算出异或和为 \(0\) 方案数,然后再改成 \(a_{n+1}=C-1\) 算出方案数,做差即是原题要求的。

怎么求异或和为 \(0\) 的方案数?其实是 这个题,可以见我在这个题的 题解。

然后考虑 \(m\not = 0\),看到有互异这个限制,很自然地直接容斥,考虑每次加入一个相等的连通块,那么容斥系数就应该是导出子图的 \(\sum\limits_{E'\in E}(-1)^{|E'|}\),观察到这个柿子在 \(|E'| \ge 1\) 的时候为 \(0\),所以只需要独立集即可,总的系数就是枚举一个包含 \(1\) 的连通块划分出去然后去计算即可。

然后考虑,如果划分的是一个偶数大小的连通块,那么这个连通块怎么划都可以,方案数为连通块最小值 \(+1\) 种方式;如果是奇数大小的,那么就需要跑我们开始的那个东西,全部乘起来的到贡献,可以做到贝尔数的复杂度。

但是我们考虑可以直接在加入连通块的时候记录最小值,这样可以做到 \(4^n\),但是还是不够快。

我们这里做一个简单的优化,我们把所有数按 \(a\) 排个序,同时集合里对于 \(\le i\) 的位,我们只记录他是否是作为最小值加入奇连通块的,而大于的就记录是否已经被加入集合。具体的,在转移的时候我们考虑 \(i\) 是否在我们枚举的集合中,如果在,那么就意味着他是通过以前被加入的,那么贡献时直接把这一位变成 \(0\) 即可;然后考虑他是最小值,如果是偶连通块,直接乘上贡献,并且加入 \(>i\) 的点,\(i\) 这一位保持 \(0\),奇连通块则变为 \(1\),可以见代码实现。这样我们就可以很方便地在最后直接拉出来哪些是需要的,复杂度是 \(O(3^nn)\)

最后再对跑出来的那些有用点集去跑 \(m=0\) 的做法就可以了,总复杂度 \(O(3^nn)\)

因为 \(a\) 可以到达 \(10^{18}\),记得取模。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5 + 5, inf = 2e9, mod = 998244353;
int n, m, c, val[maxn], coef[maxn], a[maxn];
int dp[20][2][2];
int cal(vector<int> v) {int ans = 0, s = 0;for (int i = 1; i < v.size(); i++)s ^= v[i];ans += (!s); s = 0;for (int d = 60; d >= 0; d--) {memset(dp, 0, sizeof(dp));dp[0][0][0] = 1;s = 0;int all = (1ll << d) - 1;for (int i = 1; i < v.size(); i++) {s ^= (v[i] >> d + 1);int t = ((v[i] >> d) & 1);if(!t) {for (int x = 0; x <= 1; x++)for (int y = 0; y <= 1; y++)dp[i][x][y] = dp[i - 1][x][y] * (((v[i] & all) + 1) % mod) % mod;}else {dp[i][0][0] = dp[i - 1][1][0] * (((v[i] & all) + 1) % mod) % mod;dp[i][1][0] = dp[i - 1][0][0] * (((v[i] & all) + 1) % mod) % mod;dp[i][0][1] = (dp[i - 1][1][1] * (((v[i] & all) + 1) % mod) % mod + dp[i - 1][0][1] * ((all + 1) % mod) % mod + dp[i - 1][0][0]) % mod;dp[i][1][1] = (dp[i - 1][0][1] * (((v[i] & all) + 1) % mod) % mod + dp[i - 1][1][1] * ((all + 1) % mod) % mod + dp[i - 1][1][0]) % mod;}}if(!s)ans = (ans + dp[v.size() - 1][0][1]) % mod;}return ans;
}
int solve(vector<int> v) {v.push_back(c);int ans = cal(v);if(c == 0)return ans;v[v.size() - 1]--;
//	cout << ans << " " << cal(v) << "Adsf" << endl;return (ans - cal(v) + mod) % mod;
}
int dpt[2][maxn], id[maxn], p[maxn];
bool cmp(int x, int y) {return a[x] < a[y];
}
int lowbit(int x) {return x & (-x);
}
int cnt[maxn];
signed main() {cin >> n >> m >> c;for (int i = 1; i <= n; i++)cin >> a[i], p[i] = i;sort(p + 1, p + n + 1, cmp);sort(a + 1, a + n + 1);for (int i = 1; i <= n; i++)id[p[i]] = i;for (int i = 1; i <= m; i++) {int x, y; cin >> x >> y;x = id[x], y = id[y];int s = (1 << x - 1) | (1 << y - 1);for (int t = 0; t < (1 << n); t++)if((s & t) == s)val[t]++;}for (int s = 0; s < (1 << n); s++)val[s] = !val[s], cnt[s] = cnt[s >> 1] + (s & 1);dpt[0][0] = 1;int cur = 0;for (int s = 0; s < (1 << n); s++) {coef[s] = val[s];int lb = lowbit(s);for (int t = (s - 1) & s; t; t = (t - 1) & s) {if((t & lb) == lb)coef[s] = (coef[s] - coef[t] * val[s ^ t] % mod + mod) % mod;}//	cout << s << " " << coef[s] << endl;}for (int i = 1; i <= n; i++) {cur ^= 1, memset(dpt[cur], 0, sizeof(dpt[cur]));for (int s = 0; s < (1 << n); s++) {if(!dpt[cur ^ 1][s])continue;if((s >> i - 1) & 1) {dpt[cur][s ^ (1 << i - 1)] = (dpt[cur][s ^ (1 << i - 1)] + dpt[cur ^ 1][s]) % mod;continue;}int res = (((1 << n) - 1) ^ ((1 << i) - 1));//	cout << res << endl;res = res ^ (s & res);for (int t = res; ; t = (t - 1) & res) {int u = (t | (1 << i - 1));if(cnt[u] & 1)dpt[cur][s | u] = (dpt[cur][s | u] + dpt[cur ^ 1][s] * coef[u] % mod) % mod;elsedpt[cur][s | t] = (dpt[cur][s | t] + dpt[cur ^ 1][s] * coef[u] % mod * ((a[i] + 1) % mod) % mod) % mod;if(!t)break;}//	cout << dpt[cur][9] << " " << dpt[cur ^ 1][s] << " " << s << " " << res << " " << (s | res) << "Adsf" << endl;}
//		for (int s = 0; s < (1 << n); s++)
//			cout << dpt[cur][s] << " " << i << " " << s << endl;}int ans = 0;for (int i = 0; i < (1 << n); i++) {vector<int> nw; nw.push_back(0);for (int j = 1; j <= n; j++)if((i >> j - 1) & 1)nw.push_back(a[j]);//	cout << i << " " << solve(nw) << " " << dpt[cur][i] << endl;ans = (ans + solve(nw) * dpt[cur][i] % mod) % mod;}cout << ans << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025 年筛网厂家推荐榜:聚焦场景适配与高效需求,锰钢筛网/聚氨酯筛网/合金焊接筛网/自清洁筛网/防堵筛网厂家滨州沃森网业成优选

随着矿业、建筑建材、化工、粮食加工等行业的生产效率升级,以及对物料筛选精度、设备耐用性要求的提升,筛网作为核心辅助设备,已从单一功能向 “场景化定制”“高性能适配” 方向发展。2025 年,筛网市场规模预计持…

P7076 [CSP-S2020] 动物园

题目描述 动物园里饲养了很多动物,饲养员小 A 会根据饲养动物的情况,按照《饲养指南》购买不同种类的饲料,并将购买清单发给采购员小 B。 具体而言,动物世界里存在 2k 种不同的动物,它们被编号为 0∼2k−1。动物园…

汽车价格战全面熄火了?不卷价格该卷什么? - 教程

汽车价格战全面熄火了?不卷价格该卷什么? - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

redis-4.0.11-1.ky10.sw_64.rpm安装教程(申威麒麟V10 64位系统详细步骤)

redis-4.0.11-1.ky10.sw_64.rpm安装教程(申威麒麟V10 64位系统详细步骤)​ 对 ​银河麒麟操作系统V10 64位(版本标识ky10.sw_64)​​ 的 ​Redis 4.0.11​ 软件包(文件名:redis-4.0.11-1.ky10.sw_64.rpm)的 ​超…

P10067 [CCO 2023] Real Mountains

思维训练懒得写代码了,感觉这种题还是思维为重。 我们显然需要考察两个东西:最终序列会变成啥样。 每次是如何一步一步变成最终序列的。我们先想第一个问题,显然,最终的 \(p\) 一定会是最大的那个 \(a_x\) 的 \(x\…

先辈题解

首先我们先观察到 $ 114514 $ 中只有三种数,$ 1 \(,\) 4 \(,\) 5 $,这给了我们一个思路,直接枚举这三个数代表的字母是什么,字母共有 $ 26 $ 种,所以我们的复杂度是 $ O(26^3n) $的。 code: void dfs(int s1,in…

详细介绍:并发编程原理与实战(三十三)AQS框架下手写简易可重入锁的实战解析

详细介绍:并发编程原理与实战(三十三)AQS框架下手写简易可重入锁的实战解析2025-10-14 20:13 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow…

U-Boot启动探秘:从汇编到命令行的奇幻之旅 - 指南

U-Boot启动探秘:从汇编到命令行的奇幻之旅 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

实用指南:【Lsky-Pro开源图床】Lsky-Pro+cpolar:云端素材库的远程协作方案

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

双指针的初步了解

双引用的初步了解 10.14今天在力扣上刷题,第一次了解到了双引用的概念,如图对于这个题,我一开始的思路是从0到size-1一步步遍历,如果找到值为val的,就删去,然后让计数器加1,最后输出计数器。但是不知道为什么总…

倍增并查集学习笔记

学完板子即可开始水紫题倍增并查集,可以在 \(O(m log^2 n)\) 的时间复杂度内求解 \(m\) 个诸如此类的合并问题: \[\forall \,\,\,\,\, 0 \leq i \leq k \, , \, merge(x+i,y+i) \]就真的是倍增和并查集的结合体,而不…

两数相加-leetcode

题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外…

CF2147E

给定 \(n\) 个数和 \(q\) 次查询,每次查询给定 \(k\),问最多进行 \(k\) 次以下操作后 \(n\) 个数按位或的 popcount 最大值。 令 \(ans_i\) 表示使得 \(popcount \ge i\) 至少需要几次操作,显然 \(ans_i\) 单调不降…

线程共享区域

线程共享区域🔴 线程共享区域 (Thread-Shared Areas) #JVM/线程共享区域 🔴 特点:所有线程共享同一个内存区域,需要考虑线程安全问题,是垃圾回收的主要工作区域 🔴 1. Java堆 (Java Heap) #JVM/Java堆 🔴 定…

ZR 2025 NOIP 二十连测 #1

100 + 0 + 30 + 0 = 130, Rank 72/133.大模拟!/tuu25noip二十连测day1 链接:link 题解:题目内 时间:4.5h (2025.10.14 07:40~12:10) 题目数:4 难度:A B C D\(\color{#F39C11} 橙\)*1200估分:100 + 0 + 30 + 0 =…

work1

这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/gjyycx 这个作业要求在哪里:https://edu.cnblogs.com/campus/fzu/gjyycx/homework/13558 学号:102500331 姓名:余武 安装过程:安装成功:代码结果:

2025 年液压机厂家推荐榜:伺服/小型/大型/数控/液压机厂家口碑推荐,品质可靠 聚焦智能适配,助力企业高效生产

随着制造业智能化升级、产品精度要求提升及生产效率优化需求增加,液压机作为关键成型设备,已从传统重工业领域逐步延伸至汽车零部件、五金制品、粉末冶金、电子元件等多个细分行业,2025 年市场规模预计持续扩大。但…

快速上手!山海鲸 4 种高频数据接入方式

在数据可视化实践中,“数据能顺畅接入” 是大屏发挥价值的前提。山海鲸数据可视化大屏针对不同业务场景与数据形态,推出了 4 种高频使用的数据接入方式,既降低了技术门槛,又保障了数据对接的稳定性与时效性,以下为…

AI4S Cup学习赛 - 超导体临界温度预测

AI4S Cup学习赛 - 超导体临界温度预测https://www.bohrium.com/competitions/3521345283?tab=mine

2025高级语言程序设计第一次作业lcr

班级链接:https://edu.cnblogs.com/campus/fzu/gjyycx 作业要求链接:https://edu.cnblogs.com/campus/fzu/gjyycx/homework/13558 我的学号:102500417 我的名字:刘朝榕 1.安装dev-c++2.成功安装好dev-c++3.编写示例…