首页 > 其他分享 >ABC366D 题解

ABC366D 题解

时间:2024-08-12 15:28:36浏览次数:14  
标签:前缀 题解 prefix ABC366D text Lz Lx Ly

第一眼是想写 \(kd-tree\) 的。

然后发现这就是一道三维前缀和的板子题。

三维前缀和

要想学习三维前缀和,我们首先得了解前缀和的概念,并且学会一维、二维前缀和。

什么是前缀和

前缀和是容斥原理的典型应用。这种优化方式可以使求和操作的时间复杂度降低到 \(O(1)\)(但是需要提前预处理)。

一维前缀和 & 二维前缀和

对于一维的一个序列 \(a_i\),如果我们有很多询问,每次询问让你求一个区间 \([l,r]\) 的和,我们就可以使用一维前缀和来优化。

具体地,我们设前缀序列 \(g_i = g_{i-1} + a_i\),那么不难发现,区间 \([l, r]\) 的和就是 \(g_r - g_{l - 1}\)。

对于一个二维的序列同理,我们设 \(g_{i,j} = g_{i-1,j} + g_{i,j-1} - g_{i-1,j-1} + a_{i,j}\),就可以求出任意部分的和。

一维前缀和&二维前缀和

在一维序列中,红色部分的和就是黑色部分的和减掉绿色部分的和。那么前缀和的公式就是

在二维序列中,红色部分的和就是黑色部分的和减掉绿色部分的和,然后再加上黄色部分的和(因为黄色部分被减了 \(2\) 次)。

三维前缀和

三维前缀和同理,那么下面给出三维前缀和的图。

三维前缀和

可以发现...这完全看不懂啊!

没关系,我们将它拆开研究。

我们可以看到,黑色部分包括了要求的红色部分。那么我们就可以用黑色部分减掉剩余的部分,然后求出红色部分。

我们需要减掉这三个绿色部分:

减1

减2

减3

但是这时候又会发现一个问题,绿色部分的交(如图)被重复减了。

减交

所以我们需要找到绿色部分两两的交,并且加回来。即下图的黄色部分

加1

加2

加3

这时候,我们发现还是不对,黄色部分也有交!

加交

那么我们还需要将黄色部分的交(即下图粉色部分)再减掉。

减4

那么反过来,我们也可以推出前缀和的公式:

\[g_{i,j,k} = g_{i-1,j,k}+g_{i,j-1,k}+g_{i,j,k-1}\\-g_{i-1,j-1,k}-g_{i-1,j,k-1}-g_{i,j-1,j-1}\\+g_{i-1,j-1,k-1}+a_{i,j,k} \]


然后我们来看题。

可以发现这玩意就是一道三维前缀和的板子题,非常简单。

设 \(prefix[x][y][z]\) 为从 \((1,1,1)\) 到 \((x,y,z)\) 的区域的前缀和,我们需要查询从 \((Lx, Ly, Lz)\) 到 \((Rx, Ry, Rz)\) 的子立方体的和,公式为:

\[[ \text{Sum} = \text{prefix}[Rx][Ry][Rz] ] \]

\[[ - \left( Lx > 1 ? \text{prefix}[Lx-1][Ry][Rz] : 0 \right) ] \]

\[[ - \left( Ly > 1 ? \text{prefix}[Rx][Ly-1][Rz] : 0 \right) ] \]

\[[ - \left( Lz > 1 ? \text{prefix}[Rx][Ry][Lz-1] : 0 \right) ] \]

\[[ + \left( Lx > 1 \text{ and } Ly > 1 ? \text{prefix}[Lx-1][Ly-1][Rz] : 0 \right) ] \]

\[[ + \left( Lx > 1 \text{ and } Lz > 1 ? \text{prefix}[Lx-1][Ry][Lz-1] : 0 \right) ] \]

\[[ + \left( Ly > 1 \text{ and } Lz > 1 ? \text{prefix}[Rx][Ly-1][Lz-1] : 0 \right) ] \]

\[[ - \left( Lx > 1 \text{ and } Ly > 1 \text{ and } Lz > 1 ? \text{prefix}[Lx-1][Ly-1][Lz-1] : 0 \right) ] \]


prefix[Rx][Ry][Rz] 是查询区域的总和的基础。

减去 \((Lx-1)\) 平面上的部分,表示区域中不包括 \(Lx\) 之前的部分。

减去 \((Ly-1)\) 平面上的部分,表示区域中不包括 \(Ly\) 之前的部分。

减去 \((Lz-1)\) 平面上的部分,表示区域中不包括 Lz 之前的部分。

加上 \((Lx-1, Ly-1)\) 立方体的部分,因为这个区域被多次减去了。

加上 \((Lx-1, Lz-1)\) 立方体的部分,因为这个区域被多次减去了。

加上 \((Ly-1, Lz-1)\) 立方体的部分,因为这个区域被多次减去了。

减去 \((Lx-1, Ly-1, Lz-1)\) 立方体的部分,因为这个区域被多次加回来了。

code


#include "bits/stdc++.h"

using namespace std;

const int MAXN = 100; 

int A[MAXN+1][MAXN+1][MAXN+1];

int prefix[MAXN+1][MAXN+1][MAXN+1];

int main() {
	int n, q;
	
	
	cin >> n ;
	
	// 读取三维数组数据
	for (int x = 1; x <= n; ++x) {
		
		for (int y = 1; y <= n; ++y) {
			
			for (int z = 1; z <= n; ++z) {
				
				cin >> A[x][y][z];
				
			}
		}
	}
	
	// 计算三维前缀和
	for (int x = 1; x <= n; ++x) {
		
		for (int y = 1; y <= n; ++y) {
			
			for (int z = 1; z <= n; ++z) {
				
				prefix[x][y][z] = A[x][y][z]
				
				+ (x > 1 ? prefix[x-1][y][z] : 0)
				
				+ (y > 1 ? prefix[x][y-1][z] : 0)
				
				+ (z > 1 ? prefix[x][y][z-1] : 0)
				
				- (x > 1 && y > 1 ? prefix[x-1][y-1][z] : 0)
				
				- (x > 1 && z > 1 ? prefix[x-1][y][z-1] : 0)
				
				- (y > 1 && z > 1 ? prefix[x][y-1][z-1] : 0)
				
				+ (x > 1 && y > 1 && z > 1 ? prefix[x-1][y-1][z-1] : 0);
				
			}
			
		}
		
	}
	
	cin >> q;
	
	while (q--) 
	{
		
		int Lx, Rx, Ly, Ry, Lz, Rz;
		
		cin >> Lx >> Rx >> Ly >> Ry >> Lz >> Rz;
		
		
		// 前缀和查询范围内的和
		
		int result = prefix[Rx][Ry][Rz]
		
		- (Lx > 1 ? prefix[Lx-1][Ry][Rz] : 0)
		
		- (Ly > 1 ? prefix[Rx][Ly-1][Rz] : 0)
		
		- (Lz > 1 ? prefix[Rx][Ry][Lz-1] : 0)
		
		+ (Lx > 1 && Ly > 1 ? prefix[Lx-1][Ly-1][Rz] : 0)
		
		+ (Lx > 1 && Lz > 1 ? prefix[Lx-1][Ry][Lz-1] : 0)
		
		+ (Ly > 1 && Lz > 1 ? prefix[Rx][Ly-1][Lz-1] : 0)
		
		- (Lx > 1 && Ly > 1 && Lz > 1 ? prefix[Lx-1][Ly-1][Lz-1] : 0);
		
		cout << result << endl;
	}
	
	return 0;
}


标签:前缀,题解,prefix,ABC366D,text,Lz,Lx,Ly
From: https://www.cnblogs.com/Xiang-he/p/18355037

相关文章

  • 题解:AT_abc351_f [ABC351F] Double Sum
    关于某c人士强制偷袭代码导致AT号被封,\({\color{red}\mathrm{警钟敲碎}}\)。题意一个长\(n\)的数组\(a\),求所有顺序对中两元素之差的和。分析听说有大佬2min切掉。很明显,暴力过不去。考虑计算每个元素的贡献。设\(id\)为该元素之前所有比它小的元素个数,\(sum\)表示这些......
  • tensorboard_logger库无法导入的问题解决
    一、问题描述最近在学习深度学习时,从大神们那里copy的代码中有用到tensorboard_logger这个库的东西,所以很自然地就用condainstall或者pip去安装它,但是结果是:python开源库里面没有这东西。这就让我很苦恼,所以只能自己动手,丰衣足食了。 二、解决方法首先找到tensorboard_logge......
  • ABC366 G - XOR Neighbors 题解
    发现题目实质上就是让你构造一组\(a_{1,2,\dots,n}\),有一些限制,要求一些\(a\)异或起来是\(0\)。看到\(n\le60\),果断列异或方程组,用异或高斯消元。具体地,有\(n\)个方程组,\(a_{i,j}\)表示第\(i\)个方程中\(j\)的系数。对于每一个变量\(i\),要把\(j>i\)的方程中的第......
  • 【题解】P3356 火星探险问题
    \(\large\mathfrak{1st.\Preamble|}\)前言这都什么年代了网络流24题居然还能写题解!个人认为这篇题解讲的还是比较详细的。\(\large\mathfrak{2nd.\Solution|}\)题解看到题目的第一眼,我的反应是这样的:这不跟深海机器人问题差不多吗?Ctrl-CCtrl-V秒了。不过我还是讲讲怎......
  • ABC366D 题解
    Solution题意简述给你一个正整数\(N\)和\(N^3\)个非负整数,表示为\(A_{x,y,z}\)其中\(1\leqx,y,z\leqN\)。您将得到以下格式的\(Q\)个查询,必须按顺序处理。对于第\(i\)次查询\((1\leqi\leqQ)\),您将得到一个整数元组\((Lx_i,Rx_i,Ly_i,Ry_i,Lz_i,......
  • 逆序对数列(P2513) - 题解
    [HAOI2009]逆序对数列原题链接题目描述对于一个数列\(\{a_i\}\),如果有\(i<j\)且\(a_i>a_j\),那么我们称\(a_i\)与\(a_j\)为一对逆序对数。若对于任意一个由\(1\simn\)自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为\(k\)的这样自然数数列到底......
  • ABC366F Maximum Composition 题解
    ABC366FMaximumComposition题解题目大意给定\(N\)个一次函数\(f_i(x)=a_ix+b_i\),从中选出\(K\)个函数\(f_{p_1},f_{p_2},\dots,f_{p_K}\),使得\(f_{p_1}(f_{p_2}(\dotsf_{p_K}))\)最大,求最大值。Solve考虑这样一种情况:我已经选定\(p_{k+1},p_{k+1},\dots,p_K\),现......
  • ABC366F 题解
    Solution题意简述现在有\(N\)个线性函数\(f_1,\dots,f_N\)。函数\(f_i(x)=A_ix+B_i\)。找到一个长度为\(K\)的序列\(p=(p_1,\dots,p_k)\),序列元素为\(K\)个大小在\([1,N]\)的不同整数。输出\(f_{p_1}(f_{p_2}(\dotsf_{p_k}(1)\dots))\)可能的最大值。思路贪心......
  • 爱因斯坦求和约定einsum简单例题解读
    概论在爱因斯坦求和约定或einsum()格式字符串中,所有的索引都可以分为两类:自由索引集和求和索引集。它们的区别很简单:自由索引是用于输出规范中的索引。它们与外层for循环相关联。求和索引是所有其他索引:它们出现在参数规范中,但不出现在输出规范中。之所以称为求和索引,是因......
  • ABC366E 题解
    Solution题意简述二维平面上有\(N\)个点\((x_1,y_1),\dots,(x_N,y_N)\)和一个非负整数\(D\)。求有多少对点对\((x,y)\)满足\(\sum\limits_{i=1}^N(|x-x_i|+|y-y_i|)\leD\)。思路发现\(x_i\)与\(y_i\)的捆绑关系不强(其实是几乎没有关联),所以我们分开考虑,也就是先......