BZOJ 4262 Sum | 2018 Asia Jiaozuo Regional Online C Password

12 篇文章 0 订阅
1 篇文章 0 订阅

题目链接

BZOJ 4642 Sum计蒜客 31712 Password

题目大意

给定长度为 n n n 的序列 A 1 , A 2 , ⋯   , A n A_1, A_2, \cdots, A_n A1,A2,,An,以及 m m m 组形如 ( l 1 , r 1 , l 2 , r 2 ) (l_1, r_1, l_2, r_2) (l1,r1,l2,r2) 的询问,请你对于每组询问,求出 ∑ i = l 1 r 1 ∑ j = max ⁡ { i , l 2 } r 2 f ( i , j ) \sum_{i = l_1}^{r_1} \sum_{j = \max\{i, l_2\}}^{r_2} {f(i, j)} i=l1r1j=max{i,l2}r2f(i,j) 的值,其中:

  • 对于 BZOJ 4642,有 f ( i , j ) = max ⁡ i ≤ p ≤ j { A p } − min ⁡ i ≤ q ≤ j { A q } f(i, j) = \max\limits_{i \leq p \leq j}\{A_p\} - \min\limits_{i \leq q \leq j}\{A_q\} f(i,j)=ipjmax{Ap}iqjmin{Aq} ( 1 ≤ i ≤ j ≤ n 1 \leq i \leq j \leq n 1ijn)
  • 对于 Jiaozuo Online C,有 f ( i , j ) = ( j − i + 1 ) max ⁡ i ≤ p ≤ j { A p } f(i, j) = (j - i + 1)\max\limits_{i \leq p \leq j}\{A_p\} f(i,j)=(ji+1)ipjmax{Ap} ( 1 ≤ i ≤ j ≤ n 1 \leq i \leq j \leq n 1ijn)
数据范围
  • 对于 BZOJ 4642,有 n = 1 0 5 n = 10^5 n=105, A i = ( 1023 i   m o d   10 9 )   x o r   ( 1025 i   m o d   10 9 ) A_i = ({1023}^{i} \bmod {10}^9)~\mathrm{xor}~({1025}^{i} \bmod {10}^9) Ai=(1023imod109) xor (1025imod109) ( i = 1 , 2 , … , n i = 1, 2, \ldots, n i=1,2,,n), 1 ≤ m ≤ 4 ⋅ 1 0 4 1 \leq m \leq 4 \cdot 10^4 1m4104, 1 ≤ l 1 ≤ r 1 ≤ n 1 \leq l_1 \leq r_1 \leq n 1l1r1n, 1 ≤ l 2 ≤ r 2 ≤ n 1 \leq l_2 \leq r_2 \leq n 1l2r2n
  • 对于 Jiaozuo Online C,有 1 ≤ n , m , A i ≤ 1 0 5 1 \leq n, m, A_i \leq 10^5 1n,m,Ai105 ( i = 1 , 2 , … , n i = 1, 2, \ldots, n i=1,2,,n), 1 ≤ l 1 ≤ r 1 ≤ n 1 \leq l_1 \leq r_1 \leq n 1l1r1n, 1 ≤ l 2 ≤ r 2 ≤ n 1 \leq l_2 \leq r_2 \leq n 1l2r2n
题目解法

补充定义 1 ≤ j &lt; i ≤ n 1 \leq j &lt; i \leq n 1j<in f ( i , j ) = 0 f(i, j) = 0 f(i,j)=0,则询问的值等于 ∑ i = l 1 r 1 ∑ j = l 2 r 2 f ( i , j ) \sum_{i = l_1}^{r_1} \sum_{j = l_2}^{r_2} {f(i, j)} i=l1r1j=l2r2f(i,j)。若将 f ( i , j ) f(i, j) f(i,j) 看成二维矩阵,则询问需要计算一个子矩阵的和。

尝试考虑如何用 O ( n ) \mathcal{O}(n) O(n) 的信息表示出所有的 f ( i , j ) f(i, j) f(i,j) ( 1 ≤ i , j ≤ n 1 \leq i, j \leq n 1i,jn)。不难注意到 f ( i , j ) f(i, j) f(i,j) 只和 i , j , A p , A q i, j, A_p, A_q i,j,Ap,Aq 有关。

对于每个 A p A_p Ap,我们可以利用单调栈的技巧找到最小的 x x x 和最大的 y y y 使得 x ≤ i ≤ p ≤ j ≤ y x \leq i \leq p \leq j \leq y xipjy A p A_p Ap 都是 f ( i , j ) f(i, j) f(i,j) 中对应的最大值。不过 f ( i , j ) f(i, j) f(i,j) 对应的 A p , A q A_p, A_q Ap,Aq 可能有很多个,为了避免重复统计,在这里我们约定当 p p p f ( i , j ) f(i, j) f(i,j) 中最靠左的最大值出现位置时, A p A_p Ap 才对 f ( i , j ) f(i, j) f(i,j) 产生贡献。 A q A_q Aq 的分析过程同理可得。注意到每个 A p A_p Ap(或 A q A_q Aq)的影响区域也是 f ( i , j ) f(i, j) f(i,j) 的子矩阵。

注意到统计信息是求和得出的,子矩阵 [ l 1 , r 1 ] × [ l 2 , r 2 ] [l_1, r_1] \times [l_2, r_2] [l1,r1]×[l2,r2] 的统计值,可以表示成四个子矩阵 [ 1 , r 1 ] × [ 1 , r 2 ] [1, r_1] \times [1, r_2] [1,r1]×[1,r2], [ 1 , l 1 − 1 ] × [ 1 , r 2 ] [1, l_1 - 1] \times [1, r_2] [1,l11]×[1,r2], [ 1 , r 1 ] × [ 1 , l 2 − 1 ] [1, r_1] \times [1, l_2 - 1] [1,r1]×[1,l21], [ 1 , l 1 − 1 ] × [ 1 , l 2 − 1 ] [1, l_1 - 1] \times [1, l_2 - 1] [1,l11]×[1,l21] 的统计值的组合。

同样地, A p A_p Ap(或 A q A_q Aq)对一个子矩阵 [ x 1 , y 1 ] × [ x 2 , y 2 ] [x_1, y_1] \times [x_2, y_2] [x1,y1]×[x2,y2] 产生贡献,也可以表示成它对四个子矩阵 [ x 1 , n ] × [ x 2 , n ] [x_1, n] \times [x_2, n] [x1,n]×[x2,n], [ y 1 + 1 , n ] × [ x 2 , n ] [y_1 + 1, n] \times [x_2, n] [y1+1,n]×[x2,n], [ x 1 , n ] × [ y 2 + 1 , n ] [x_1, n] \times [y_2 + 1, n] [x1,n]×[y2+1,n], [ y 1 + 1 , n ] × [ y 2 + 1 , n ] [y_1 + 1, n] \times [y_2 + 1, n] [y1+1,n]×[y2+1,n] 分别产生贡献。

经过上述等价改写后,我们只需要考虑每个产生贡献的矩阵 [ x 1 , n ] × [ x 2 , n ] [x_1, n] \times [x_2, n] [x1,n]×[x2,n] 对每个询问统计值的矩阵 [ 1 , r 1 ] × [ 1 , r 2 ] [1, r_1] \times [1, r_2] [1,r1]×[1,r2] 产生了多少相应的贡献,这里的贡献是 f ( i , j ) f(i, j) f(i,j) 中不属于最值的那部分信息,举例来说:

  • 对于 BZOJ 4262,最大值的贡献是 1 1 1,最小值的贡献是 − 1 -1 1
  • 对于 Jiaozuo Online C,最大值的贡献是 ( j − i + 1 ) (j - i + 1) (ji+1)

其中 x 1 ≤ i ≤ r 1 x_1 \leq i \leq r_1 x1ir1, x 2 ≤ j ≤ r 2 x_2 \leq j \leq r_2 x2jr2

问题化简为在二维偏序上容易统计的信息,我们可以将这些信息,即 ( x 1 , x 2 ) (x_1, x_2) (x1,x2) ( r 1 , r 2 ) (r_1, r_2) (r1,r2),首先关于第一维进行排序,然后用类似归并排序的过程将其重新关于第二维排序。在归并排序合并每个区间划分的两个子区间分别排序后的有序表过程中,统计前面区间中贡献矩阵(数点)对后面区间中询问矩阵(数点)的贡献。具体来说:

  • 对于 BZOJ 4262,贡献矩阵和询问矩阵交集部分所产生的最大值贡献中贡献的系数是 ∑ i = x 1 r 1 ∑ j = x 2 r 2 1 = ( r 1 + 1 ) ( r 2 + 1 ) − ( r 2 + 1 ) x 1 − ( r 1 + 1 ) x 2 + x 1 x 2 \sum_{i = x_1}^{r_1} \sum_{j = x_2}^{r_2}{1} = (r_1 + 1)(r_2 + 1) - (r_2 + 1) x_1 - (r_1 + 1) x_2 + x_1 x_2 i=x1r1j=x2r21=(r1+1)(r2+1)(r2+1)x1(r1+1)x2+x1x2,那么维护前面区间中第二维取值不超过 k k k 的所有贡献矩阵对应的 ∑ v \sum{v} v, ∑ x 1 v \sum{x_1 v} x1v, ∑ x 2 v \sum{x_2 v} x2v, ∑ x 1 x 2 v \sum{x_1 x_2 v} x1x2v 就能方便地求出后面区间中每个询问矩阵获得的贡献,其中 v v v 是相应的最大值、最小值或者它们的相反数
  • 对于 Jiaozuo Online C,相应的系数是 ∑ i = x 1 r 1 ∑ j = x 2 r 2 ( j − i + 1 ) \sum_{i = x_1}^{r_1} \sum_{j = x_2}^{r_2}{(j - i + 1)} i=x1r1j=x2r2(ji+1),是一个关于 v v v, x 1 v x_1 v x1v, x 2 v x_2 v x2v, x 1 2 v x_1^2 v x12v, x 2 2 v x_2^2 v x22v, x 1 x 2 v x_1 x_2 v x1x2v, x 1 2 x 2 v x_1^2 x_2 v x12x2v, x 1 x 2 2 v x_1 x_2^2 v x1x22v 的多项式,分别维护即可。
代码实现

由于解法的部分内容留给读者推导,为了不做出剧透,这里仅给出 BZOJ 4262 的实现。对于 Jiaozuo Online C,还需要注意答案可能超过 2 63 2^{63} 263,但不会超过 ( 2 64 − 1 ) (2^{64} - 1) (2641)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = (int)1e5 + 1, maxm = maxn << 4 | 1;
int m, low, upp, etot, ord[maxm], que[maxm];
LL ans[maxn];
struct Event {
	int typ, x, y;
	LL v;
} eve[maxm];
bool cmp(int const &u, int const &v) {
	if(eve[u].x != eve[v].x)
		return eve[u].x < eve[v].x;
	if(eve[u].y != eve[v].y)
		return eve[u].y < eve[v].y;
	return eve[u].typ < eve[v].typ;
}
void addEvent(int typ, int x, int y, int v) {
	if(x < low || x > upp || y < low || y > upp || !v)
		return;
	ord[etot] = etot;
	eve[etot++] = (Event){typ, x, y, (LL)v};
}
void solve(int L, int R) {
	if(L == R)
		return;
	int M = (L + R) >> 1;
	solve(L, M);
	solve(M + 1, R);
	LL cnt[5] = {};
	for(int i = L, j = M + 1, k = 0; i <= M || j <= R; ) {
		int u = ord[i], v = ord[j];
		if(j > R || (i <= M && eve[u].y <= eve[v].y)) {
			if(!eve[u].typ) {
				LL v0 = eve[u].v, v1 = v0 * eve[u].x, v2 = v0 * eve[u].y, v3 = v1 * eve[u].y;
				cnt[0] += v0;
				cnt[1] += v1;
				cnt[2] += v2;
				cnt[3] += v3;
			}
			que[k++] = ord[i++];
		} else {
			if(eve[v].typ) {
				LL v3 = 1;
				LL v2 = -eve[v].x - 1;
				LL v1 = -eve[v].y - 1;
				LL v0 = v2 * v1;
				ans[eve[v].typ] += eve[v].v * (cnt[0] * v0 + cnt[1] * v1 + cnt[2] * v2 + cnt[3] * v3);
			}
			que[k++] = ord[j++];
		}
	}
	memcpy(ord + L, que, (R - L + 1) * sizeof(int));
}
void solve() {
	sort(ord, ord + etot, cmp);
	int tot = 0;
	for(int i = 0; i < etot; ) {
		int typ = eve[ord[i]].typ, x = eve[ord[i]].x, y = eve[ord[i]].y;
		LL v = 0;
		for( ; i < etot && eve[ord[i]].typ == typ && eve[ord[i]].x == x && eve[ord[i]].y == y; ++i)
			v += eve[ord[i]].v;
		if(v)
			eve[ord[tot++]] = (Event){typ, x, y, v};
	}
	if(tot)
		solve(0, tot - 1);
}
int main() {
	static int seq[4][maxn], *a = seq[0], *pL = seq[1], *pR = seq[2], *stk = seq[3];
	scanf("%d", &m);
	low = maxn;
	upp = 0;
	for(int i = 1; i <= m; ++i) {
		scanf("%d%d%d%d", seq[0] + i, seq[1] + i, seq[2] + i, seq[3] + i);
		low = min(low, min(seq[0][i], seq[2][i]));
		upp = max(upp, max(seq[1][i], seq[3][i]));
	}
	for(int i = 1; i <= m; ++i) {
		int &xL = seq[0][i], &xR = seq[1][i], &yL = seq[2][i], &yR = seq[3][i];
		addEvent(i, xR, yR, 1);
		addEvent(i, xL - 1, yR, -1);
		addEvent(i, xR, yL - 1, -1);
		addEvent(i, xL - 1, yL - 1, 1);
	}
	for(int i = 1, u = 1, v = 1, p = (int)1e9; i <= upp; ++i) {
		u = (((LL)u << 10) - u) % p;
		v = (((LL)v << 10) + v) % p;
		a[i] = u ^ v;
	}
	for(int i = low, sz = 0; i <= upp; ++i) {
		for( ; sz && a[stk[sz - 1]] < a[i]; --sz);
		pL[i] = sz ? stk[sz - 1] + 1 : low;
		stk[sz++] = i;
	}
	for(int i = upp, sz = 0; i >= low; --i) {
		for( ; sz && a[stk[sz - 1]] <= a[i]; --sz);
		pR[i] = sz ? stk[sz - 1] - 1 : upp;
		stk[sz++] = i;
		addEvent(0, pL[i], i, a[i]);
		addEvent(0, pL[i], pR[i] + 1, -a[i]);
		addEvent(0, i + 1, i, -a[i]);
		addEvent(0, i + 1, pR[i] + 1, a[i]);
	}
	for(int i = low, sz = 0; i <= upp; ++i) {
		for( ; sz && a[stk[sz - 1]] > a[i]; --sz);
		pL[i] = sz ? stk[sz - 1] + 1 : low;
		stk[sz++] = i;
	}
	for(int i = upp, sz = 0; i >= low; --i) {
		for( ; sz && a[stk[sz - 1]] >= a[i]; --sz);
		pR[i] = sz ? stk[sz - 1] - 1 : upp;
		stk[sz++] = i;
		addEvent(0, pL[i], i, -a[i]);
		addEvent(0, pL[i], pR[i] + 1, a[i]);
		addEvent(0, i + 1, i, a[i]);
		addEvent(0, i + 1, pR[i] + 1, -a[i]);
	}
	solve();
	for(int i = 1; i <= m; ++i)
		printf("%lld\n", ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值