首页 > 其他分享 >高维前缀和

高维前缀和

时间:2024-04-12 21:14:17浏览次数:19  
标签:前缀 复杂度 容斥 mathcal sum 高维

by TheBigYellowDuck

相关链接:[[状态压缩]]

前置知识

高维前缀和是一类解决子集问题的方法。

考虑二维前缀和

\[S(i,j)=S(i-1,j)+S(i,j-1)-S(i-1,j-1)-a_{i,j} \]

但是这么容斥,在维数很高的时候会很复杂。

我们考虑另一种求法:

for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        a[i][j] += a[i - 1][j];
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        a[i][j] += a[i][j - 1];

这样也能达到求前缀和的效果。这样的前缀和是由零维到一维再到二维累加起来的。

同理,考虑三维前缀和。

for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        for (int k = 1; k <= n; k++)
            a[i][j][k] += a[i - 1][j][k];
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        for (int k = 1; k <= n; k++)
            a[i][j][k] += a[i][j - 1][k];
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        for (int k = 1; k <= n; k++)
            a[i][j][k] += a[i][j][k - 1];

对于高维前缀和,我们令集合 \(S\) 的大小为它的维数,那么从 \(|S|-1\) 维前缀和推到 \(|S|\) 维前缀和就是这样的。

for (int j = 0; j < n; j++)
    for (int i = 0; i < (1 << n); i++)
        if (i >> j & 1)
            f[i] += f[i ^ (1 << j)];

应用在子集问题中,这样做的时间复杂度为 \(\mathcal{O}(n2^n)\),比暴力枚举子集的 \(\mathcal{O}(3^n)\) 要优秀。

同时,如果做高维后缀和,相当于求超集的答案。

for (int j = 0; j < n; j++)
    for (int i = 0; i < (1 << n); i++)
        if ((i >> j & 1) == 0)
            f[i] += f[i | (1 << j)];

ARC100E Or Plus Max

很奇妙的一道题。

\(i\operatorname{or}j\leq k\) 很奇怪,考虑转化为 \(i\operatorname{or}j=k\) 的答案,求前缀最大值即可。

\(i\operatorname{or}j=k\) 还是很不好,考虑转化为 \(i,j\subseteq k\)。这样的 \(i,j\) 一定满足 \(i\operatorname{or}j\leq k\),也是合法的。

这样就变成正常的子集问题了。用高维前缀和维护每个集合的最大值和次大值即可。

时间复杂度 \(\mathcal{O}(n2^n)\)。

Submission #46181257 - AtCoder Regular Contest 100

CF449D Jzzhu and Numbers

考虑容斥。先建出容斥模型。

  • 每个元素为一种选取方案。全集 \(U\) 为所有选取方案构成的集合。
  • 元素 \(A\) 的第 \(i\) 种属性为 \(a\in A\) 按位与之和的二进制第 \(i\) 位上为 \(0\)。
  • \(S_i\) 为具有第 \(i\) 种属性的元素构成的集合。

设二进制最高位为 \(m\),我们要求的就是

\[\left|\bigcap_{i=1}^m S_i\right| \]

对这个东西容斥一下。

\[\left|\bigcap_{i=1}^m S_i\right|=|U|+\sum_{k=1}^m(-1)^k\sum_{a_i<a_{i+1}}\left|\bigcap_{i=1}^k\overline{S_{a_i}}\right| \]

这里的 \(\overline {S_i}\) 就是按位与之和第 \(i\) 位上为 \(1\) 的选取方案的集合。

枚举二进制集合 \(S\),要求 \(i\in S\) 位上都为 \(1\) 的选取方案数,相当于求按位与之和包含 \(S\) 的选取方案数。而按位与之和包含 \(S\),又要求每个数都包含 \(S\)。

设 \(f(S)\) 为包含 \(S\) 的数的个数,\(g(S)\) 为按位与之和包含 \(S\) 的选取方案数,则有

\[g(S)=2^{f(S)}-1 \]

而 \(g(S)\) 其实就是容斥式子中 \(k\) 个集合的交的大小。也就是说

\[\sum_{|S|=k} g(S)=\sum_{a_i<a_{i+1}}\left|\bigcap_{i=1}^k\overline{S_{a_i}}\right| \]

代入回容斥的式子当中

\[\left|\bigcap_{i=1}^m S_i\right|=|U|+\sum_{k=1}^m(-1)^k\sum_{|S|=k} g(S) \]

问题就变成了求解 \(f(S)\)。而这就是一个超集和,用高维后缀和就可以解决。

时间复杂度 \(\mathcal{O}(m2^m)=\mathcal{O}(n\log n)\)。

提交记录

P6442 [COCI2011-2012#6] KOŠARE

取出元素并集为全集,可以对元素取反,这样就转化为了取出元素交集为空。

那就跟上一道题完全一样了。

时间复杂度 \(\mathcal{O}(m2^m)\)。

提交记录

CF383E Vowels

容斥,考虑求不包含任何一个元音字母的单词数。

枚举字符集 \(S\),那么不合法的单词就会被包含在 \(\overline S\) 中。只需要求每个字符集包含的单词数。

做一遍高维前缀和就做完了。

令 \(\Sigma\) 为字符集大小,时间复杂度 \(\mathcal{O}(n+|\Sigma|2^{|\Sigma|})\)。

提交记录

CF165E Compatible Numbers

\(a\operatorname{and}b=0\) 说明 \(b\in \overline a\)。做高维前缀和即可。输出满足要求的数只需要微调一下。

时间复杂度 \(\mathcal{O}(n\log n)\)。

提交记录

标签:前缀,复杂度,容斥,mathcal,sum,高维
From: https://www.cnblogs.com/duckqwq/p/18132089

相关文章

  • leetcode热题HOT 208. 实现 Trie (前缀树)
    一、问题描述:Trie(发音类似“try”)或者说前缀树是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。请你实现Trie类:Trie()初始化前缀树对象。voidinsert(Stringword)向前缀树中插入字符串wor......
  • 为什么索引结构默认使用B+Tree?为什么需要注意联合索引中的顺序?最左前缀原则是什么?
    (1)为什么索引结构默认使用B+Tree,而不是B-Tree,Hash,二叉树,红黑树?B-tree:B+Tree相比于B-Tree,所有的数据都存储在叶子节点,并且叶子节点之间用指针相连形成了一个有序链表,这有利于范围查询和全表扫描时连续地读取磁盘上的数据,极大地降低了磁盘I/O次数。而在B-Tree中,数据分布在所有节......
  • 小红不想做莫比乌斯反演杜教筛求因子和的前缀和(枚举)--牛客周赛 Round 39-E
    #include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineendl'\n'#defineinf1e18constintmod=1e9+7;constintN=2e5+5;intn,m,p,x;voidsolve(){ cin>>n>>m>>p>>x; intans=0; for(inti=1;i&......
  • 差分和前缀和——蓝桥杯备赛
    一、大学里的树木要打药问题描述教室外有N棵树,根据不同的位置和树种,学校要对其上不同的药。因为树的排列成线性,且非常长,我们可以将它们看作一条直线给他们编号。树的编号从0∼N−1且N<1e6。对于树的药是成区间分布,比如3∼5号的树靠近下水道,所以他们要用驱蚊虫的药,20......
  • 9. 景区导游-树上前缀和&&最近公共祖先
    9.景区导游-蓝桥云课(lanqiao.cn)641211313423524632651#include<bits/stdc++.h>#defineintlonglong#defineendl'\n'usingnamespacestd;//tu动态数组用来存图,相当于一条绳子上面有好几个结,每个结都各自连了一条链子//vector<pair<t......
  • 前缀和
    题目LeetCode力扣难度303.RangeSumQuery-Immutable303.区域和检索-数组不可变......
  • 208. 实现 Trie (前缀树)
    classTrie{Trie[]chs=newTrie[26];intcnt=0;publicTrie(){}publicvoidinsert(Stringword){Trieroot=this;for(charch:word.toCharArray()){if(root.chs[ch-'a']==null){......
  • 前缀异或和
    异或是可以用前缀和来维护的,因为异或有一个重要的性质x^x=0设preXor[i]=a[0]^a[1]^a[2]^a[3]^a[4]^.....^a[i]那么给定一个[l,r]范围的区间求a[l,r]的异或和,我们就可以利用前缀异或和来求解preXor(l,r)=preXor(0,r)^preXor(0,l-1)=preXor[r]^p......
  • Leetcode 【930. 和相同的二元子数组】【统计「优美子数组」】【974. 和可被 K 整除的
    这道题目是经典的求子数组之和=goal的个数,用map维护。但是笔者在实现的过程中发现0的情况不是很好出来,问题在于mp[sum]和sum+=num的代码语句存在位置问题。后来看了下代码还是自己没有考虑清楚。这种类型的题目就是要想清楚你的做法,以及边界条件。classSolution{public:......
  • SDC可伸缩的高维约束基准和算法
    可伸缩的高维约束基准和算法​ 在过去二十年里,进化约束多目标优化受到了广泛的关注和研究,并且已经提出了一些基准测试约束多目标进化算法(CMOEAs)。特别地,约束函数与目标函数值有紧密的联系,这使得约束特征太单调并且与真实世界的问题不同。因此,之前的CMOEAs不能特别好的解决现实......