古典叙事 · 技术札记

序章

山河有卷
人间有声

写代码,也写长风、旧城与未熄的灯。
愿每一篇随笔,都有自己的山水与回声。
阅览随笔

J - 乌龟与最大公约数

题解:最大化分割子集和的 GCD

题目解析

给定连续整数集合 \(\{a,\ a+1,\ a+2,\ \dots,\ a+b-1\}\),将其分成两个非空子集,求两个子集和的最大公约数的最大可能值

枚举

首先我们考虑暴力,枚举子集的复杂度为\(2^n\),故不行,所以我们考虑优化。

核心数学推导

  1. 计算全集总和
    连续 \(b\) 个数的和:

\[S = a + (a+1) + \dots + (a+b-1) = \frac{b \cdot (2a + b - 1)}{2} \]

  1. 关键性质1
    设两个子集和为 \(S_1, S_2\),则 \(S_1 + S_2 = S\)
    对任意公约数 \(d\),满足 \(d \mid S_1\)\(d \mid S_2\),则必然有 \(d \mid S\)

因此:答案一定是总和 \(S\) 的约数,我们只需要找 \(S\)最大合法约数

  1. 合法条件
  • 子集非空 → 不能取 \(d=S\)(会导致一个子集和为 \(0\)
  • 最优解:\(S\) 的最大真约数(即 \(S\) 除以其最小质因子)

解题思路

首先我们计算S的所有因数,S是n个数的总和,因为关键性质1,所以答案一定在S的因数中
然后我们枚举S的所有因数,对于每一个因数判断它是否能成为答案。
我们如何判断可以尽可能的快呢。
我们发现当我们从集合中选取一个数的时候,我能选取的范围是\((a,a+b-1)\)
选取两个数的范围为\((2a+1,2a+2b-3)\);
同样,所以我拿走n个集合中的数可组成的和的范围为前面n项的和到最后面n和之间;
只要这个区间内出现了一个我们当前枚举的因数或者他的倍数,这个因数就可以成为答案;
我的代码用了前缀和,如果用等差公式求和也是一样的;
pre[j] % it >= (pre[b] - pre[b - j]) % it || pre[b] - pre[j] - pre[b - j] >= it;
或者可以写成
(pre[b]-pre[j])/it-pre[j]/it>0;
答案就合法

完整 AC 代码(C++)


#include<iostream>
#include<string>
#include<algorithm>
#include <vector>
#include <cmath>
using namespace std;
using i64 = long long;
i64 pre[300005];
i64 a, b,t;
void solve() {
	
	cin >> a >> b;
	i64 sum = (a + a + b - 1) * b / 2;
	vector<i64> cnt;
	for (i64 i = 1; i * i <= sum; i++) {//记得i要开long long 不然会爆int
		if (sum % i == 0)
		{
			cnt.push_back(i);
			cnt.push_back(sum / i);
		}
	}
	pre[0] = 0;
	for (int i = 1; i <= b; i++) {
		pre[i] = pre[i - 1] + i + a - 1;
	}
	sort(cnt.begin(), cnt.end());
	i64 ans = 0;
	for(auto it:cnt)
	{
		i64 v = 0;
		for (int j = 1; j < b; j++) {
		if (pre[j] % it >= (pre[b] - pre[b - j]) % it || pre[b] - pre[j] - pre[b - j] >= it) {
			v = 1;
				break;
			}
		}
		if (v == 1) {
			ans = max(ans, it);
		}
	}
	cout << ans << '\n';
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> t;
	while(t--){
		solve();
	}
}
posted @ 2026-04-04 09:05  Morphis‘  阅读(2)  评论(0)    收藏  举报

特别策划 · CINEMATIC NOTES

风沙与孤骑

风起塞外,
胜负在刀剑之前。

“把复杂拆成秩序,把未知写成答案。”
Morphis · 山河一卷 愿你从这里出发,仍能听见山风。 影像:farfarSébastien Goldberg / Unsplash