高维前缀和

我们先看一维前缀和

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

那么二维前缀和

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

这个是根据容斥计算的,维度很高的时候就不行了
我们换一种方法

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

也就是对每一维分别做前缀和
那么高维前缀和呢?
它是解决以下问题的

例题

已知一个序列a0−2n−1a_{0-2^n-1}a0−2n−1​,对于每一个i∈0,n−1i\in0,n-1i∈0,n−1

∑j∣i==iaj\sum_{j|i==i}a_jj∣i==i∑​aj​
也就是求它的子集的权值和
直接子集枚举做是3n3^n3n的,我们需要更快的算法
考虑刚才前缀和的过程,发现对于二进制而言,它的子集一定是它的前缀和中的
因为一定会有某一位比这个数小,所以是前缀和
但是我们不可能按照容斥做法做前缀和,因此就对每一维做前缀和

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

复杂度O(n2n)O(n2^n)O(n2n)
类似的,有下面的问题
已知一个序列a0−2n−1a_{0-2^n-1}a0−2n−1​,对于每一个i∈0,n−1i\in0,n-1i∈0,n−1

∑j&i==iaj\sum_{ j\& i==i}a_jj&i==i∑​aj​
也就是询问超集的权值和,对应到上面就是高维后缀和,和前缀和是类似的

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

高维差分

因为差分和前缀和是逆运算,所以就有了下面的代码

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

这个东西又被称作sosdp

[ARC100C] Or Plus Max

题目传送门

注意到我们只需要求出
iorj==ki \;or j==kiorj==k
的最大值,取个前缀max就行了
但是这样也不好求,我们考虑继续转化为
iorj∈ki\;or j\in kiorj∈k
也就是k的子集,这个东西显然小于等于k,也是合法的
那么i,j显然也是k的子集,也就是说我么需要从k的子集中挑出最大值和次大值就行啦
那么我们知道前缀和不仅可以知道“和”,也可以知道前缀max之类的
那么我们只需要对于每一个k,求出他子集的最大和次大就可以了
可以用高维前缀和

#include<bits/stdc++.h>
using namespace std;
const int N = 19;
const int M = (1<<N);
typedef long long LL;
#define PII pair<LL,LL>
#define X(x) x.first
#define Y(x) x.second
PII Merge(PII A,PII B)
{PII res=A;if(X(B)>X(A)){X(res)=X(B);Y(res)=max(X(A),Y(B));} else Y(res)=max(Y(A),X(B));return res;
}
PII f[M];
int main()
{int n;cin>>n;int m=(1<<n);for(int i=0;i<m;i++){LL a;scanf("%lld",&a);f[i]=make_pair(a,(LL)-1e9+7);}for(int i=0;i<n;i++)for(int j=0;j<m;j++)if((j>>i)&1) f[j]=Merge(f[j],f[j-(1<<i)]);LL ans=X(f[0])+Y(f[0]);for(int i=1;i<m;i++){ans=max(ans,X(f[i])+Y(f[i]));printf("%lld\n",ans);}return 0;
}

CF1208F Bits And Pieces

题目传送门

考虑可以枚举i
位运算的最大值,考虑按位填数
从高到低遍历每一位
判断是不是能找到一个就j,k
使得当前的答案ans∈j&kans\in j\&kans∈j&k,如果能,这一位填1,否则是0
显然j&kj\&kj&k是ansansans的超集,因此j,kj,kj,k都是ansansans的超集
而我们只需要找到最靠右的j,kj,kj,k判断是不是大于i就可以了
可以用高维后缀和处理

#include<bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define mk(a,b) make_pair(a,b)
#define X(a) a.first
#define Y(a) a.second
const int K = 21;
const int N = 1e6+7;
PII f[(1<<K)+9];
void up(int s,int pos)
{if(pos==X(f[s])||pos==Y(f[s])||pos==-1) return;if(X(f[s])==-1) X(f[s])=pos;else {if(pos>X(f[s])) {Y(f[s])=X(f[s]);X(f[s])=pos;}else{if(Y(f[s])==-1) Y(f[s])=pos;else Y(f[s])=max(Y(f[s]),pos);}}
}
int a[N];
int main()
{int n;for(int i=0;i<(1<<21);i++)f[i]=mk(-1,-1);cin>>n;for(int i=1;i<=n;i++){scanf("%d",&a[i]);up(a[i],i); }for(int i=0;i<21;i++)for(int j=0;j<(1<<21);j++)if(!((j>>i)&1)) {up(j,X(f[j+(1<<i)]));up(j,Y(f[j+(1<<i)]));}int Ans=0;for(int i=1;i<=n-2;i++){int ans=0;for(int p=20;p>=0;p--){if((a[i]>>p)&1) continue;int s=ans+(1<<p);int x=X(f[s]),y=Y(f[s]);if(x>i&&y>i) ans=s;}Ans=max(Ans,ans|a[i]);}cout<<Ans;return 0;
}

CF165E Compatible Numbers

题目传送门


很简单,只需要判断aia_iai​的补集的子集是不是全为空就行了

#include<bits/stdc++.h>
using namespace std;
const int K =22;
const int N = 1e6+7;
int f[(1<<K)+9];
void up(int s,int x)
{if(!f[s]) f[s]=x;
}
int a[N];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){scanf("%d",&a[i]);up(a[i],a[i]);}for(int i=0;i<22;i++)for(int j=0;j<(1<<22);j++)if((j>>i)&1) up(j,f[j-(1<<i)]);for(int i=1;i<=n;i++){int s=a[i],t=(((1<<22)-1)^s);int j=f[t];if(j==0) printf("-1 ");else printf("%d ",j);}return 0;
}

CF383E Vowels

题目传送门

直接求不是很好求,考虑容斥
用总的单词个数n,减掉一个元音也没包含的个数
一个元音也没包含,相当于是当前元音集合补集的子集
用高维前缀和就可以处理了

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL K =24;
const LL N = 1e6+7;
LL f[(1<<K)+9];
void up(LL s,LL v)
{f[s]=f[s]+v;
}
LL a[N];
char s[50];
int main()
{LL n;cin>>n;for(LL i=1;i<=n;i++){scanf("%s",s+1);LL S=0;for(LL j=1;j<=3;j++){LL c=s[j]-'a';if(s[j]>'x') continue;S=S|(1<<c);}up(S,1);}for(LL i=0;i<24;i++)for(LL j=0;j<(1<<24);j++)if((j>>i)&1) up(j,f[j-(1<<i)]);LL Ans=0;for(LL S=0;S<(1<<24);S++){LL T=((1<<24)-1)-S;LL cnt=n-f[T];Ans=Ans^((LL)cnt*cnt);}cout<<Ans;return 0;
}

CF449D Jzzhu and Numbers

题目传送门

设f(i)=∑j=1n[i&aj==i]f(i)=\sum_{j=1}^n[i \& a_j ==i]f(i)=∑j=1n​[i&aj​==i]
可以高维前缀和处理
设g(i)g(i)g(i)为选出一个子序列使得子序列j1,j2……j_1,j_2……j1​,j2​……
满足i∈aji&aj2……i\in a_{j_i}\&a_{j_2}……i∈aji​​&aj2​​……的方案数
那么显然是2f(i)−12^{f(i)}-12f(i)−1
我们是h(i)h(i)h(i)为题目与的值是i的答案,题目所求即为h(0)h(0)h(0)
那么g(i)=∑i&j==ih(j)g(i)=\sum_{i\&j==i}h(j)g(i)=∑i&j==i​h(j)
也就是高维后缀和,我们直接来一个高维后缀差分就可以的到h啦

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
const int K = 20;
const int M = (1<<K)+9;
typedef long long LL;
const int mod = 1e9+7;
LL Pow[N];
LL f[M],g[M];
int main()
{int n;cin>>n;Pow[0]=1;for(int i=1;i<=n;i++){Pow[i]=Pow[i-1]*2ll%mod;LL a;scanf("%lld",&a);f[a]++;}for(int i=0;i<20;i++)for(int j=0;j<(1<<20);j++)if(!((j>>i)&1)) f[j]=(f[j]+f[j+(1<<i)]);for(int i=0;i<(1<<20);i++)g[i]=(Pow[f[i]]-1+mod)%mod;for(int i=0;i<20;i++)for(int j=0;j<(1<<20);j++)if(!((j>>i)&1)) g[j]=(g[j]-g[j+(1<<i)]+mod)%mod;cout<<g[0];return 0;
}

sosdp(高维前缀和)学习笔记相关推荐

  1. cidr斜线记法地址块网络前缀_学习笔记之《计算机网络》- 网络层(一)

    1.网络层概述 网络层主要任务是实现网络互连,进而实现数据包在各网络之间的传输. 网络层需要解决的主要问题: 网络层向运输层提供怎样的服务(可靠传输,还是不可靠传输) 网络层寻址问题 路由选择问题 2 ...

  2. 多维前缀和 学习笔记 模板及例题

    一维前缀和大家都会,二维就更好理解了. 一维初始化: for(i=1;i<=n;i++){q[i]=(q[i-1]+a[i]);} 二维初始化其实花个图就可以了,这里直接上模板: q[1][1] ...

  3. 高维统计学习笔记1——LASSO和Oracle性质

    高维统计学习笔记1--LASSO和Oracle性质 主要参考资料:Sara Van De Geer<Estimation and Testing Under Sparsity> 前言 当年 ...

  4. ESL2.5 高维问题的局部方法学习笔记(含泛化误差分解MSE分解)

    2.5 高维问题的局部方法 这是一篇有关<统计学习基础>,原书名The Elements of Statistical Learning的学习笔记,该书学习难度较高,有很棒的学者将其翻译成 ...

  5. 《MySQL实战45讲》——学习笔记04-05 “深入浅出索引、最左前缀原则、索引下推优化“

    04 | 深入浅出索引(上) 1. 什么是索引? 索引的出现其实就是为了提高数据查询的效率,就像书的目录一样,书有500页,每页存的都是书的内容,目录可能只有5页,只存了页码:通过目录能快速找到某个主 ...

  6. 高等数值计算方法学习笔记第6章【解线性代数方程组的迭代方法(高维稀疏矩阵)】

    高等数值计算方法学习笔记第6章[解线性代数方程组的迭代方法(高维稀疏矩阵)] 一.引言 1.例题(说明迭代法的收敛性研究的重要性) 2.定义(迭代法,迭代法收敛)&解误差 二.基本迭代法 1. ...

  7. matlab学习笔记11_2高维数组操作 squeeze,ind2sub, sub2ind

    一起来学matlab-matlab学习笔记11 11_2 高维数组处理和运算 squeeze, ind2sub, sub2ind 觉得有用的话,欢迎一起讨论相互学习~ squeeze 删除单维度–B= ...

  8. matlab学习笔记11_3高维数组操作 filp, shiftdim, size, permute, ipermute

    一起来学matlab-matlab学习笔记11 11_3 高维数组处理和运算 filp, shiftdim, size, permute, ipermute 觉得有用的话,欢迎一起讨论相互学习~ fi ...

  9. 史上最全C语言学习笔记

    最全C语言学习笔记 学习目标 学习编程最主要目标 分析问题的能力.构造算法的能力.编程的能力. 调试程序的能力. 学习方法手段 如何操作? 解题思路:重点要放在解题的思路上 一开始就要学会看懂程序,编 ...

最新文章

  1. C语言编写的PHP框架--yaf入门编程
  2. 藏在正则表达式里的陷阱
  3. java 定时_结合真实案例,清晰梳理几种定时任务的退出「JAVA并发」
  4. pytorch 冻结层操作 + 学习率超参数设置
  5. C++:cin、cin.getline()、getline()的用法
  6. excel 中的文本是ansi还是unicode_详细讲解Excel中常用的文本函数
  7. OFFICE——Word与Excel交互处理——邮件合并
  8. flink的savepoint实验-java
  9. 新手学html 第一节:html简介
  10. Linux启动和退出系统的方法,实验二 Linux的启动与关闭
  11. python_vlc 播放http流
  12. javaScript常见的五种数组去重(转载)
  13. PAIP.自定义SELECT BOX COMMBO BOX展现.txt
  14. Svn下载及安装(附带汉化包安装)
  15. 触摸屏坏了有哪些现象_手机屏坏了有什么现象
  16. 陈佼每周一蛋疼:“哼唱搜索”更像是个玩具
  17. 知识蒸馏 | 知识蒸馏的算法原理与其他拓展介绍
  18. 京东把 Elasticsearch 用得真牛逼!日均5亿订单查询完美解决!
  19. Tomcat 8.5 HTTP 报文只返回200 不返回 OK
  20. 谈谈百度搜索解封经验与技巧(转)

热门文章

  1. 去哪儿网支付系统架构演进(上)
  2. python怎么取共轭_python矩阵运算,转置,逆运算,共轭矩阵实例
  3. 51nod 1298
  4. 英文写作:讨论的中文逻辑是什么?讨论怎么写?
  5. 挫败感的来源自哪里?
  6. 使用Masonry布局后不能立即获取到frame
  7. mysql+check+男或女_关于MYSQL 检察check约束
  8. Swarm Flocking 经典蜂拥模型大全
  9. 2014小米,百度,pptv,去哪儿笔试题目回忆
  10. 如何设置网站的URL路径