1. 程式人生 > 其它 >高維字首和學習筆記

高維字首和學習筆記

高維字首和,也稱 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);
	}
}