NOIP 2023 模拟赛五 题解

A. [NOIP 2023 模拟赛五 By FXT A] 简单数学题

summarization

给出一个值域为 \([1,m]\) 的正整数序列 \(a_{1\sim n}\),序列中的数各不相同,求出使 \(a_i^2+a_j\) 为完全平方数的 \((i,j)\) 的对数。

solution

实际上就是求 \(x^2+y=z^2\quad(x,y,z\in\mathbb{N}^+)\)\((x,y)\),其中 \(x,y\) 需要在序列中存在。

变形为 \(y=(z+x)(z-x)\),考虑 \(y\) 的所有成对因数。

枚举 \(y\),分解 \(y=a\times b\quad(a<b,a,b\in\mathbb{N}^+)\),根据 \(z+x=b,z-x=a\),求出 \(z,x\),最后统计答案。

由于枚举 \(y\) 太慢,考虑枚举因数 \(i\),再枚举 \(i\) 的倍数 \(ki\quad(k\ge2,ki\le m,k\in\mathbb{N}^+)\)

code

CI N = 1e6; int n, m, Tng[N + 5];
int main () {
	RI i, j; for (Read (n, m), i = 1; i <= n; ++ i) {int x; Read (x); ++ Tng[x];}
	ll ans = 0; for (i = 1; i <= N; ++ i) for (j = i; j <= N; j += i) {
		int minn = min (i, j / i), maxx = max (i, j / i); if ((maxx - minn) % 2 == 0) ans += Tng[j] * Tng[(maxx - minn) / 2];
	} ans /= 2; printf ("%lld\n", ans);
	return 0; 
}

B. [NOIP 2023 模拟赛五 By FXT B] 简单第三题

summarization

给出一个 \(1\)\(N\) 的排列,你需要求出有多少个区间 \([L,R]\),满足这个区间的值是连续的。比如 \(2,3,1\) 是一个合法的区间,而 \(3,1\) 不是。(\(1\le N\le3\times10^5\)

solution1

考虑分治,将 \([L,R]\) 范围的答案拆为 \([L,mid],[mid+1,R]\quad(mid=\frac{L+R}2)\) 的答案和跨越 \(mid\) 的连续的区间的个数,所以只需 \(\mathcal{O}(n)\) 求出在 \([L,R]\) 范围内跨越 \(mid\) 的连续的区间的个数。

首先,对于一个区间 \([L,R]\) 是连续的,它的充要条件是 \(\text{最大值}-\text{最小值}=R-L\)

所以考虑预处理出两个数组 \(mx_i,mn_i\)\(mx_i\) 表示在 \(1\le i\le mid\) 范围内,\([L,mid]\) 区间的后缀最大值和在 \(mid+1\le i\le R\) 范围内,\([mid+1,R]\) 区间的前缀最大值。\(mn_i\) 同理。

那么对于 \([L,R]\) 中一个区间 \([i,j]\quad(L\le i\le mid< j\le R)\),成为连续区间的条件变为:

\[max(mx_i,mx_j)-min(mn_i,mn_j)=j-i \]

考虑分类讨论 \(max(mx_i,mx_j)\)\(min(mn_i,mn_j)\) 的取值情况。

一、\(max(mx_i,mx_j)=mx_i,min(mn_i,mn_j)=mn_i\)

发现 \(j=i+mx_i-mn_i\),枚举 \(i\) 判断合法情况即可

二、\(max(mx_i,mx_j)=mx_j,min(mn_i,mn_j)=mn_j\)

同一。

三、\(max(mx_i,mx_j)=mx_i,min(mn_i,mn_j)=mn_j\)

发现 \(mx_i+i=mn_j+j\)。先固定 \(i\),观察满足此情况时的不等条件:

\[\begin{aligned} mx_i>mx_j\\ mn_i>mn_j \end{aligned} \]

由于 \(mx_j\) 单调不减,\(mn_j\) 单调不增,所以满足上式的 \(j\) 一定在一个区间 \([l,r)\quad(mid+1\le l<r\le R+1)\) 中,其中 \(l,r\) 满足 \(mn_i>mn_l,mn_i<mn_{l-1},mx_i>mx_{r-1},mx_i<mx_r\)

\(i\) 左移一位后,\(mx_i\) 增加或不变,\(mn_i\) 减小或不变。发现 \(l,r\) 都需要向右移以满足新的不等条件。

于是将 \(i\)\(mid\) 一位一位移到 \(L\),过程中维护 \(j\) 取值的区间,将在区间范围内的 \(j\)\(mn_j+j\) 加入桶中,查询 \(mx_i+i\) 即可。桶的更新只需要在移动 \(l,r\) 时加入一个或删除一个即可。

四、 \(max(mx_i,mx_j)=mx_j,min(mn_i,mn_j)=mn_i\)

同三。

复杂度 \(\mathcal{O}(n)\)

分治算法总复杂度 \(\mathcal{O}(n\log n)\)

code1

CI N = 3e5; int n, a[N + 5], mx[N + 5], mn[N + 5], Tng[N * 3 + 5]; ll ans = 0;
void solve (int L, int R) {
	RI i, j; if (L == R) return ; int mid = (L + R) >> 1; solve (L, mid); solve (mid + 1, R); mx[mid] = mn[mid] = a[mid]; mx[mid + 1] = mn[mid + 1] = a[mid + 1];
	for (i = mid - 1; i >= L; -- i) mx[i] = max (mx[i + 1], a[i]), mn[i] = min (mn[i + 1], a[i]);
	for (i = mid + 2; i <= R; ++ i) mx[i] = max (mx[i - 1], a[i]), mn[i] = min (mn[i - 1], a[i]);
	for (i = L; i <= mid; ++ i) {j = i + mx[i] - mn[i]; if (j > mid && j <= R && mx[i] > mx[j] && mn[i] < mn[j]) ++ ans;}
	for (j = mid + 1; j <= R; ++ j) {i = j - mx[j] + mn[j]; if (i <= mid && i >= L && mx[i] < mx[j] && mn[i] > mn[j]) ++ ans;}
	int l = mid + 1, r = mid + 1; for (i = mid; i >= L; -- i) {
		W (r <= R && mx[r] < mx[i]) ++ Tng[mn[r] + r + N], ++ r;
		W (l < r && mn[l] > mn[i]) -- Tng[mn[l] + l + N], ++ l;
		ans += Tng[mx[i] + i + N];
	} W (l < r) -- Tng[mn[l] + l + N], ++ l;
	l = mid, r = mid; for (j = mid + 1; j <= R; ++ j) {
		W (l >= L && mx[l] < mx[j]) ++ Tng[mn[l] - l + N], -- l;
		W (l < r && mn[r] > mn[j]) -- Tng[mn[r] - r + N], -- r;
		ans += Tng[mx[j] - j + N];
	} W (l < r) -- Tng[mn[r] - r + N], -- r;
}
int main () {
	RI i, j; for (Read (n), i = 1; i <= n; ++ i) Read (a[i]); solve (1, n); printf ("%lld\n", ans + n);
	return 0; 
}
posted @ 2023-05-14 22:24  ClapEcho233  阅读(116)  评论(0编辑  收藏  举报