CF2013E Prefix GCD

【题目大意】

给定一个长度为 n n n 的数列 a 1 … n a_{1 \dots n} a1n,你可以将 a 1 … n a_{1 \dots n} a1n 按照任意顺序进行重排,使得:

∑ i = 1 n gcd ⁡ { a 1 , a 2 , a 3 , … , a n } \sum\limits_{i=1}^{n}\gcd\left \{ a_{1},a_{2},a_{3},\dots,a_{n}\right \} i=1ngcd{a1,a2,a3,,an}

最小。其中 gcd ⁡ { a 1 , a 2 , … , a n } \gcd\left \{ a_{1},a_{2},\dots,a_{n}\right \} gcd{a1,a2,,an} 表示 a 1 , a 2 , … , a n a_{1},a_{2},\dots,a_{n} a1,a2,,an 的最大公因数。

【输入格式】

第一行一个整数 t t t,表示共有 t t t 组数据。

每组数据第一行一个整数 n ( 1 ≤ n ≤ 1 × 1 0 5 ) n(1 \leq n \leq 1 \times 10^{5}) n(1n1×105),表示数列的长度。

第二行 n n n 个整数,表示 a 1 … n a_{1 \dots n} a1n。保证 1 ≤ a i ≤ 1 × 1 0 5 1 \leq a_{i} \leq 1 \times 10^{5} 1ai1×105

保证所有测试数据的 n n n max ⁡ 1 ≤ i ≤ n { a i } \max\limits_{1 \leq i \leq n}\left \{ a_{i}\right \} 1inmax{ai} 的总和不会超过 1 × 1 0 5 1 \times 10^{5} 1×105

【输出格式】

t t t 行,每行一个整数,表示答案。

【样例解释】
  • 对于第一组测试数据,你可以以 [ 2 , 4 , 2 ] [2,4,2] [2,4,2] 的顺序重排数列,这样答案为 2 + 2 + 2 = 6 2+2+2=6 2+2+2=6 最小。
  • 对于第三组测试数据,你可以以 [ 6 , 10 , 15 ] [6,10,15] [6,10,15] 的顺序重排数列,这样答案为 6 + 2 + 1 = 9 6+2+1=9 6+2+1=9 最小。

Translated by HPXXZYY, not by ChatGPT.

和洛谷上的翻译大体相同,因为是同一个人翻译的。

[Analysis] \color{blue}{\texttt{[Analysis]}} [Analysis]

这题可以贪心。

正解就是把最小的 a i a_{i} ai 放到最前面,然后每次选取和它的 gcd 最小的那一个数。

可是,为什么这样是对的?

先证明把最小的 a i a_{i} ai 放在最前面最优。

先证明引理:若 a < b a<b a<b,有 a + gcd ⁡ ( a , b ) ≤ b a+\gcd(a,b) \leq b a+gcd(a,b)b

我们知道 gcd ⁡ ( a , b ) = gcd ⁡ ( a , b − a ) = gcd ⁡ ( b , b − a ) ≤ ( b − a ) \gcd(a,b)=\gcd(a,b-a)=\gcd(b,b-a)\leq (b-a) gcd(a,b)=gcd(a,ba)=gcd(b,ba)(ba),所以 a + gcd ⁡ ( a , b ) = a + gcd ⁡ ( a , b − a ) ≤ a + ( b − a ) = b a+\gcd(a,b)=a+\gcd(a,b-a) \leq a+(b-a) = b a+gcd(a,b)=a+gcd(a,ba)a+(ba)=b

所以,如果将较大的 a k a_{k} ak 放在前面的话,我们来看一张图(假设 A A A 是最小的元素):

在这里插入图片描述

我们可以发现,上面蓝色部分对应的 1 , 2 , 3 1,2,3 1,2,3(代表算到这个数时的前缀 gcd),会分别大于等于下面红色的 1 , 2 , 3 1,2,3 1,2,3。且上面蓝色算到 A A A 的前缀 gcd 至少为 1 1 1。所以上面的蓝色的前缀 gcd 和为 b + 1 + 2 + 3 + 4 ≥ b + 1 + 2 + 3 + 1 b+\color{blue}{1+2+3+4} \geq b+\color{blue}{1+2+3}\color{black}{+1} b+1+2+3+4b+1+2+3+1。但是下面的前缀 gcd 的和为 a + gcd ⁡ ( a , b ) + 1 + 2 + 3 ≤ b + 1 + 2 + 3 a+\gcd(a,b)+\color{red}{1+2+3} \color{black}{\leq b+}\color{blue}{1+2+3} a+gcd(a,b)+1+2+3b+1+2+3。所以显然下面的情况更优。

后面的贪心过程同理可以证明。

由于每次取 gcd 都会比上一次至少减少一半,所以时间复杂度为 O ( n log ⁡ max ⁡ { a i } ) O(n \log \max\{a_{i}\}) O(nlogmax{ai})

Code \color{blue}{\text{Code}} Code

const int N=1e5+100;
typedef long long ll;

const int inf=0x3f3f3f3f;

int n,a[N],lst,now,T;
ll ans;

int HPXXZYY(){
	n=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	
	sort(a+1,a+n+1);
	
	if (n==1) return printf("%d\n",a[1]);
	
	now=a[1];
	for(int i=2;i<=n;i++)
		now=gcd(now,a[i]);
	
	ans=1ll*now*n+(a[1]-now);
	
	lst=a[1];
	int tmp=now;
	while (true){
		now=inf;
		for(int i=1;i<=n;i++)
			now=min(now,gcd(lst,a[i]));
		
		lst=now;
		ans+=lst-tmp;
		
		if (lst==tmp) break;
	}
	
	return printf("%lld\n",ans);
}

int main(){
	T=read();
	while (T--) HPXXZYY();
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值