NOIP 2023 模拟赛五 题解

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

summarization

给出一个值域为 [1,m] 的正整数序列 a1n,序列中的数各不相同,求出使 ai2+aj 为完全平方数的 (i,j) 的对数。

solution

实际上就是求 x2+y=z2(x,y,zN+)(x,y),其中 x,y 需要在序列中存在。

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

枚举 y,分解 y=a×b(a<b,a,bN+),根据 z+x=b,zx=a,求出 z,x,最后统计答案。

由于枚举 y 太慢,考虑枚举因数 i,再枚举 i 的倍数 ki(k2,kim,kN+)

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

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

solution1

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

首先,对于一个区间 [L,R] 是连续的,它的充要条件是 最大值最小值=RL

所以考虑预处理出两个数组 mxi,mnimxi 表示在 1imid 范围内,[L,mid] 区间的后缀最大值和在 mid+1iR 范围内,[mid+1,R] 区间的前缀最大值。mni 同理。

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

max(mxi,mxj)min(mni,mnj)=ji

考虑分类讨论 max(mxi,mxj)min(mni,mnj) 的取值情况。

一、max(mxi,mxj)=mxi,min(mni,mnj)=mni

发现 j=i+mximni,枚举 i 判断合法情况即可

二、max(mxi,mxj)=mxj,min(mni,mnj)=mnj

同一。

三、max(mxi,mxj)=mxi,min(mni,mnj)=mnj

发现 mxi+i=mnj+j。先固定 i,观察满足此情况时的不等条件:

mxi>mxjmni>mnj

由于 mxj 单调不减,mnj 单调不增,所以满足上式的 j 一定在一个区间 [l,r)(mid+1l<rR+1) 中,其中 l,r 满足 mni>mnl,mni<mnl1,mxi>mxr1,mxi<mxr

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

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

四、 max(mxi,mxj)=mxj,min(mni,mnj)=mni

同三。

复杂度 O(n)

分治算法总复杂度 O(nlogn)

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 @   ClapEcho233  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示