2 条题解
-
4
序列奇偶
题目描述:
有 个数字,第 个数字 的范围在 ,有 个限制,第 个限制要求 。
求有多少合法序列以及最小字典序合法序列。
。
暴力可以获得 的分数。
我们发现 个条件都与 有关,于是我们考虑之前确定每一个数字的奇偶性,并计算每一个数字为偶数的方案数 ,奇数的方案数 ,计算公式如下:
$$\begin{aligned} a_{i,1}&=\lfloor\frac{(y_i-x_i+1)+(x_i\bmod 2)}{2}\rfloor\\ a_{i,0}&=(y_i-x_i+1)-a_{i,1} \end{aligned}$$于是原问题被转化为一个 序列,要求一段区间的异或值为定值,求方案数和转化为原序列之后的最小字典序序列。
直接枚举可以获得 的分数。
然后我们可以作一遍前缀异或和,记 。
然后限制条件就变为 。这个时候我们可以考虑将 向 连边权值为 。之后用带权并查集维护 表示 和 所在集合的根的奇偶性相同/不同。
带权并查集:
如果设 表示 和并查集中 的父亲 的奇偶性的异或情况,那么 应该为 到根的边的异或值。
那么执行 函数时,设当前 的参数为 ,则应该有 。时时刻刻维护这个值就行。
实际实现时可以偷懒,因为合并时必然是 和 之间直接执行 ,所以我们可以把 数组和 数组合并为一个数组。
注意每次调用 前要先用 ,不然可能使用的是一个未更新的值。
int getf(int x){ if(f[f[x]]==f[x])return f[x]; int t=getf(f[x]); val[x]^=val[f[x]]; return f[x]=t; }然后是合并函数 。
不妨设 的根为 ,表示 和 的奇偶性的异或为 。
首先如果说 和 不相等,此时只需要知晓 和 之间的关系就行。容易发现 。
然后就是 和 不相等。此时需要判断有没有矛盾出现。若 则没有矛盾,反之亦然。
void add(int x,int y,int S){ int X=getf(x),Y=getf(y); if(X!=Y){ val[Y]=S^val[x]^val[y]; sz[X]+=sz[Y]; f[Y]=X; } else{ if(val[x]^val[y]^S) flag=1; } }此时如果出现了矛盾,可以直接判断出无解。
接着考虑如何计数。
注意到所有的点分为两类:
- 没有点与这个点有关系,这是自由点。
- 不是自由点,即连通块大小至少为 。
注意到第一种完全独立,很好处理;第二种连通块的个数不超过 ,即 。此时可以暴力枚举所有可能性,然后 DP 第一种即可。
具体的,设 表示前 个点, 。则:
- 若 属于第一种,则枚举 ,有 。
- 否则,设 必须选 ,则只能枚举 ,有 。且 。
然后此时最终答案就是 ,边界条件 。
第一问就做完了。
第二问比较简单。你可以从前往后贪心选择,容易发现每个点只会有两个选择,即 和 。
每次先选 ,然后使用带权并查集看是否有矛盾。如果有则 ,否则 。
这样就做完了。
-
0
pts is very easy, I'll don't say anything.
Easily notice that we should used DSU to confirm if it is valid (solution exists).
So, as we all know 扩展并查集可用带权值替代。
Let as 的前缀异或的值, 为并查集的基础数组,目标数组为
若让 。
则 。
显然随便维护。
所以,不难发现,我们如果确定联通块的根,显然确定整个联通快。
Counting problem:
DP,DFS,calculate
如果直接决策孤立点,枚举其他的根。发现复杂度正确 。
随后,计算非孤立点的值。
最后,DP即可。令 表示第 个的 的方案数。
转移显然,孤立点随便,非孤立点满足 。
此时,注意当前 的取值需要乘法一下。记录 为奇数, 为偶数是简单的。区间多少个奇数/偶数
第一问做完。
第二问类似,反过来 DP, 再从前向后决策就行了。
- 1
信息
- ID
- 2744
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 9
- 标签
- (无)
- 递交数
- 33
- 已通过
- 4
- 上传者