高维前缀和学习笔记

背景:

GDSOI \text{GDSOI} zsyz \text{zsyz} 全挂, OZYrank16 \text{OZYrank16} 卡线没进。
看了师兄们的游记,发现一些好东西没学。

正题:

先考虑容斥的做法。
一维的做法:

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

二维的做法:

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

三维的做法:

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

. . . ...
假设维数为 T T
如此的时间复杂度是 Θ ( n T 2 T ) \Theta(n^T*2^T) 的。
很不优秀啊。


其实有更好的做法。
一维的做法:

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

二维的做法:

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

三维的做法:

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

. . . ...
其实很好理解。
你考虑先解决一维,再将这个结果继承到下一维,如此类推。
时间复杂度: Θ ( T n T ) \Theta(Tn^T)
利用这个东西,就可以算出高维前缀和。高维前缀和一般都是 n = 2 n=2 的情况,一般来说就是求一个集合的子集这类的东西。
over. \text{over.}

猜你喜欢

转载自blog.csdn.net/zsyz_ZZY/article/details/89847243