高维前缀和学习笔记

高维前缀和,也称 SOSDP。
首先考虑一维的前缀和怎么做。
\(sum_i=sum_{i-1}+a_i\)
再考虑二维,我们常用的是根据容斥来写的:
\(sum_{i,j}=sum_{i,j-1}+sum_{i-1,j}-sum_{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];

但到了 \(n\) 维,这样做的时间复杂度是 \(n^n\)。显然是不够优的。
高维前缀和应运而生。
我们考虑将每个维度压成一个二进制位。
那么当一位为 \(1\) 时,就要从 \(0\) 转移过来。
核心代码:

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

例题

AT4168 [ARC100C] Or Plus Max

我们可以将问题转化为求出最大的 \(a_i+a_j\) 满足 \(i \ or \ j \subset k\)
那么我们对于每个 \(k\) 求出其子集的最大值和次大值,然后答案即为前缀 \(max\)

Code

//LYC_music yyds!
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0)
#define lowbit(x) (x&(-x))
#define int long long
using namespace std;
int read()
{
	int pos=1,num=0;
	char ch=getchar();
	while (!isdigit(ch))
	{
		if (ch=='-') pos=-1;
		ch=getchar();
	}
	while (isdigit(ch))
	{
		num=num*10+(int)(ch-'0');
		ch=getchar();
	}
	return pos*num;
}
void write(int x)
{
	if (x<0)
	{
		putchar('-');
		write(-x);
		return;
	}
	if (x>=10) write(x/10);
	putchar(x%10+'0');
}
void writesp(int x)
{
	write(x);
	putchar(' ');
}
void writeln(int x)
{
	write(x);
	putchar('\n');
}
const int N=(1<<20)-1;
int n,ans;
pair<int,int> a[N];
pair<int,int> merge(pair<int,int> x,pair<int,int> y)
{
	if (x.first<y.first) swap(x,y);
	pair<int,int> res=x;
	if (y.first>res.second) res.second=y.first;
	return res;
}
signed main()
{
	n=read();
	for (int i=0;i<1<<n;i++)
		a[i]=make_pair(read(),-0x3f3f3f3f3f3f3f3f);
	for (int j=0;j<n;j++)
		for (int i=0;i<1<<n;i++)
			if (i&(1<<j)) a[i]=merge(a[i],a[i^(1<<j)]);
	for (int i=1;i<1<<n;i++)
	{
		ans=max(ans,a[i].first+a[i].second);
		writeln(ans);
	}
}
posted @ 2021-09-01 13:32  dd_d  阅读(120)  评论(0)    收藏  举报