题解:lo6878 生不逢时

news/2025/11/7 22:17:57/文章来源:https://www.cnblogs.com/LUlululu1616/p/19201035

写这篇题解的时候回酒店电脑崩了直接没了,也算是照应标题生不逢时了……

牛牛题。

题意:给定正整数 n, m 和 n 个区间,第 i 个区间为 \([l _ i, r _ i]\),保证 \(0 \leq l_i \leq r_i < 2^m\)

对于非负整数 \(x\),记 \(S _ m(x)\) 表示 \(x\) 在二进制下最低的 \(m\) 位依次连接成的 \(01\) 串,如果不足 \(m\) 位则在高位补 \(0\)

对于 \(k = 1, 2, \cdots ,n\),求有多少非负整数序列 \(a _ 1, a _ 2, \cdots, a _ k\) 满足下列条件。

  • 对于所有 \(1 \leq i \leq k,l _ i \leq a _ i \leq r _ i\)
  • \(S _ m(a _ 1 \oplus a _ 2 \oplus \cdots \oplus a _ k)\) 是回文串,其中 \oplus 表示按位异或运算。

答案对 \(998244353\) 取模。

做法:

首先考虑处理回文,直接考虑把高的一半位对称下来,那么这样就要求异或和为 \(0\) 且我们以后可以不用再考虑高位的事情。

然后就是考虑把 \([l_i,r_i]\) 分解成 $\log $ 个区间,这些区间形如 \([a_1,a_1+2^{d_1}),[a_2,a_2+ 2^{d_2})\cdots\),并且满足 \(a_i+2^{d_i}=a_{i+1}\)\(d_i\) 为最大的满足 \(2^{d_i}|a_i,a_i+2^{d_i}\le r_i+1\)。发现这些区间在把高位对称下来后还是区间,所以也可以不用管高位的事情了。

注意到这些区间满足前若干位固定,后若干位随意,我们这里用 \((x,l)\) 来指代一个固定位为 \(x\),后 \(l\) 位的区间,所以 \([l_i,r_i]\) 就可以被分解为若干个 \((a_j,d_j)\)

考虑如何合并两个区间的结果,假设为 \((x_1,l_1),(x_2,l_2)\)。发现 \(l\) 应该取 \(\max(l_1,l_2)\),因为短的那一边随便取,长的那一边一定可以任意取。而 \(x\) 就应该取 \(x_1,x_2\) 将后 \(l\) 位置成 \(0\) 后异或在一起,也比较显然。

根据上面这个东西可以直接列出来一个暴力的 dp,\(dp_{i,j,S}\) 代表考虑了前 \(i\) 个,目前得到结果为 \((S, j)\)。转移就是枚举一个区间然后直接合并即可,可以做到 \(O(\log^n V)\)

但是我们考虑一个事情,我们还有另外一种计算的方式,我们可以枚举 \(j\) 再考虑对应的 \(S\) 有多少种。观察到,对于一个 \([l_i,r_i]\),其区间应该是一直加 lowbit 然后再补齐 \(r\) 中少的。对于一个 \(j\),前后两个阶段中只会至多分别有一种 \(S\) 出现。所以如果最后答案 \((x,l)\)\(l=j\),则 \(x\) 其实只有 \(2^n\) 种取法!所以我们直接对于每个位置 \(i\),后 \(j\) 位随意的时暴力算出来高位的情况,然后只要求有多少种方案异或和为 \(0\) 即可。

所以我们现在只要干这么一些事情:

  1. 把所有区间分解一下。

  2. 注意到两个数异或卷积后再末尾置零和置零后再异或没区别,同时注意到补 lowbit 和补 \(r\) 两部分数其实是子集关系,也就是说,在 Trie 树上形如两条链。所以我们卷积的时候直接卷就可以。

  3. 因为我们要求的是 \(\max = j\) 的情况,所以考虑直接枚举确定位为全 \(0\) 的情况即可。

然后直接上一个 meet in middle 就可以做到 \(O(2^{\frac n 2}m)\) 的复杂度。。主要就是第三步的时候等于我要合并两个部分,枚举两侧固定为都是 \(x\),然后对于 \(\max\) 的解决考虑容斥,考虑在子树内选两个点的方案数再减去都选在儿子里没有选 \(j\) 的情况即可。细节可以见代码是怎么用类似 Trie 的东西维护这个。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 45, N = 1.2e8 + 5, mod = 998244353;
int n;
long long l[maxn], r[maxn], m, all, All, inv[maxn * 2];
long long rev(long long v, int l, int r) {long long res = 0;for (int i = l; i <= r; i++)res <<= 1, res |= ((v >> i) & 1);return res;
}
struct node {int son[2];long long val;
} ;
struct Trie {node tr[N];queue<int> ers;inline int newnode() {int p;if (!ers.empty())p = ers.front(), ers.pop();elsep = ++tot;return p;}int tot, rt1, rt2, p, q;void add(long long l, long long r, long long x, long long y, int &t) {if (!t)t = newnode();//  cout << l << " " << r << " " << x << " " << y << endl;tr[t].val += y - x + 1, tr[t].val %= mod;//  cout << l << " " << r << " " << tr[t].val << endl;if (x <= l && r <= y)return ;long long mid = l + r >> 1;if (x <= mid)add(l, mid, x, y, tr[t].son[0]);if (mid < y)add(mid + 1, r, x, y, tr[t].son[1]);}void mrg(int x, int y, int &rt) {if (!x || !y)return ;if (!rt)rt = newnode();tr[rt].val = (tr[rt].val + 1ll * tr[x].val * tr[y].val % mod) % mod;for (int xx = 0; xx <= 1; xx++)for (int yy = 0; yy <= 1; yy++)mrg(tr[x].son[xx], tr[y].son[yy], tr[rt].son[xx ^ yy]);}void update(long long l, long long r, long long x, long long y, int &rt, int d) {//  if(l != r)//      cout << l << " " << r << " " << x << " " << y << endl;if (x <= l && r <= y) {long long w = (l & all) ^ rev(l, (m + 1) / 2, m - 1);//  cout << l << " " << r << " " << x << " " << y << " " << w << " " << d << " " << rev(l, m / 2, m - 1) << " " << l << " " << m / 2 + 1 << endl;w = (w >> d) << d;//  cout << w << " " << d << endl;add(0, all, w, w + (1ll << d) - 1, rt);return ;}long long mid = l + r >> 1;if (x <= mid)update(l, mid, x, y, rt, d - 1);if (mid < y)update(mid + 1, r, x, y, rt, d - 1);}int query(long long l, long long r, int p, int q, int d) {//  cout << l << " " << r << " " << p << " " << q << " " << tr[p].val << " " << tr[q].val << " " << tr[p].son[0] << " " << tr[q].son[0] << endl;if (!p || !q)return 0;long long mid = l + r >> 1;return ((query(l, mid, tr[p].son[0], tr[q].son[0], d - 1) + query(mid + 1, r, tr[p].son[1], tr[q].son[1],d - 1)) % mod +(1ll * tr[p].val * tr[q].val % mod -1ll * (tr[tr[p].son[0]].val + tr[tr[p].son[1]].val) % mod * (tr[tr[q].son[0]].val + tr[tr[q].son[1]].val) %mod) * inv[d + 1] % mod + mod) % mod;}void clear(int u) {if (tr[u].son[0])clear(tr[u].son[0]);if (tr[u].son[1])clear(tr[u].son[1]);tr[u].son[0] = tr[u].son[1] = tr[u].val = 0;}
} tree;
signed main() {cin >> n >> m;inv[0] = 1;for (int i = 1; i <= m; i++)inv[i] = inv[i - 1] * (mod + 1) / 2 % mod;for (int i = 1; i <= n; i++)cin >> l[i] >> r[i];all = (1ll << m / 2) - 1, All = (1ll << m) - 1;tree.add(0, all, 0, 0, tree.rt1), tree.add(0, all, 0, 0, tree.rt2);for (int i = 1; i <= n; i++) {tree.p = tree.q = 0;swap(tree.rt1, tree.rt2);//  cout << 123 << endl;tree.update(0, All, l[i], r[i], tree.p, m);//  cout << 123 << endl;tree.mrg(tree.rt1, tree.p, tree.q);swap(tree.rt1, tree.q);tree.clear(tree.p), tree.clear(tree.q);cout << tree.query(0, all, tree.rt1, tree.rt2, m / 2 - 1) << endl;}return 0;
}

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

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

相关文章

【UEGamePlay】- 3C篇(三) : 角色 (二)

前言 上篇文章我们大体梳理了角色相关的移动/旋转框架逻辑,并且初步筛选了我们

stapter WP笔记

很喜欢的靶机,有效暴露了自己的不足,里面的兔子洞基本上全部踩了一遍,所以写一下这篇wp兼笔记 感想:打靶很多时候是反直觉的,有的时候不能基于感觉,或者说觉得概率很小就不去尝试,它是一个严谨的,纯粹理性的过…

【51单片机】【protues仿真】基于51单片机全自动洗衣机系统 - 教程

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

定金单专题

一、系统中的定金单,支付方式和账户是一一对应的。 二、定金单的支付方式,再Payment method grouping里面是以Card形式出现的,否则定金单的支付找不到对应的支付方式。 三、在系统中下定金单。

练习上传

这是一级标题 MPE教程 这是二级标题 这是三级标题 这会是 斜体 的文字 这会是 斜体 的文字 这会是 粗体 的文字 这会是 粗体 的文字 你也 组合 这些符号 这个文字将会被横线删除 无序列表Item 1 Item 2Item 2a Item 2b…

uniapp修改原生导航栏样式、加图标、加文字、加点击事件 - 详解

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

CITP——更适合约束接口的CRTP变式 - CLimber

在C++中,前人已经提出了多种约束接口的方式。其中,CRTP不妨是一个适用于低标准且不需要性能的静态多态设计方式。但CRTP无法约束构造函数,实现过程涉及静态转换,代码复杂。为此,我们提出了CRTP的变式——**CITP**…

函数的可变参数传参

一.前言 可变参数传参是C语言的一种高级用法。二. 用法示例 求任意个 int 类型数据的平均值。点击查看代码 double avg_int(int count, ...) {va_list ap; /* 2. 声明参数列表变量 */int sum = 0;va…

P12366 [蓝桥杯 2022 省 Python B] 数位排序

将数字与数位和捆绑(使用结构体或元组)放入数组或列表,以数位和为关键字排序,最后输出第 m 个数。 #include<stdio.h> #include<algorithm> using namespace std; const int MAXN=1e6+7; struct Node{…

重组蛋白表达技术|HEK293细胞蛋白表达|高效重组蛋白生产服务

一、表达系统的技术特性与选择策略 哺乳动物细胞表达系统以其卓越的翻译后修饰能力成为复杂蛋白表达的首选方案。其中,HEK293细胞凭借高转染效率和快速生长特性,在瞬时表达中表现优异;而CHO细胞则因其在悬浮培养中的…

CJI8运行查询没有数据

CJI8运行查询没有数据,发现不是权限问题,是因为查询界面设置的问题。如下: To view the entire transfer in CJI8, the report must be executed for Overall values without the year. ☆ No matter how much you …

Para 集训

Para 给我推的高质量题目,终于是找时间整理出来了。Para 好闪,拜谢 Para!Para 最好啦! [清华集训 2014] 主旋律 abs,第一题就忘了怎么做了。 DAG 计数模板题。 这里有一个经典的 trick:不是强连通分量的总会存在…

RK3576在智能工程机械中的应用|三屏八摄AI视觉解决方案

一、工程机械智能化的加速趋势近年来,随着人工智能与边缘计算的深入融合,工程机械行业正迎来从“机械化”到“智能化”的转型浪潮。无论是挖掘机、装载机、塔吊,还是矿卡、摊铺机等重型设备,智能控制、实时监控与人…

贪心,排序,二分,分治

题目描述 马上就要放暑假啦! 为了激励一下公司的员工,徐老师决定给所有人发奖金! 发奖金的方式非常简单,徐老师会在桌上一字排开 \(n\) 张纸团,每张纸团上会写着一个数字 \(a_i\),为了平衡公司成本,这里的数字可…

python01

练习编程语言:是我们与计算机交流的介质 编程:用编程语言写出一个个文件,最后达到我们的目的 编程有什么用:让计算机来帮我们干活 因为了解清楚才能学好所以引出下面的内容。 计算机组成原理 控制器 类似于大脑来控…

C语言实现数据结构顺序表

1.顺序表的定义 线性表可分为两种存储结构,一种是顺序存储结构,一种是链式存储结构。一般来说,顺序表是一个相同数据类型的集合,且内存地址一定相邻。在C语言中,一般使用数组实现。 2.顺序表的存储结构 使用结构体…

AI Compass前沿速览:Cursor 2.0、Firefly Image5、Agent HQ 、LongCat-Video、Kimi-k2 Thinking

AI Compass前沿速览:Cursor 2.0、Firefly Image5、Agent HQ 、LongCat-Video、Kimi-k2 ThinkingAI Compass前沿速览:Cursor 2.0、Firefly Image5、Agent HQ 、LongCat-Video、Kimi-k2 Thinking AI-Compass 致力于构建…

25.11.7联考题解

A 简单题,考虑一个串变化后不同并且计数不重不漏只须保证区间两端不同即可。 B 简单贪心。shopping plans 的超级弱化版。 C 设 \(f_i\) 表示被分在 \(\le i\) 的 L 型的方案数,显然有 \(f_i=\left(\sum_{j=x-i}^{x-…

浅谈dp中的最优化、计数问题

前言 诚然,这东西本来是一个挺好的东西的,但是如果它染上了数学,那么就不那么好了。 我承认,我的分类和题目选取是不够全面、不够有代表性的,因为这只是写给我自己看的。 这东西有三个难点:状态,转移,优化。(…