P5334数组题解

我来 C tj 了

这无疑是一片没有人想看的 TJ,hehe。

但是做法真的特别简单,虽然是错解,有点玄学部分,谨慎观看。

题意就不说了,还是比较明显的。

那么首先来说一下特判答案为 -1 的情况,容易发现当所有数都拥有相同的质因子,那么无论怎么操作,都不可能将所有数变为 1。这里讲完了。

然后我们知道根据贪心策略,我们一定会将某一个数变为 1 后再将其余数变为 1,而将某个数变为 1 一定是将某个区间所有的操作最后推到这个数上,也就是说,这个数会变为某个区间的所有的数的 gcd,这个数是啥不重要,重要的是究竟是哪个区间。

我们再转换一下题意,其实已经很明显了,就是求最短的区间 gcd 为 1 的区间的长度。

赛事写了个 \(O(n^2)\) 的写法,就是枚举区间的 gcd ,区间 gcd 用 ST 表预处理可以 \(O(1)\) 得到应该都知道。然后呢,根据直觉,答案区间长度一定不会太长,所以我们先枚举区间长度,然后如果找到了合法区间,就直接退出,因为此时一定是最优的,后面的都不用看。

但是,注意到有可能这个序列本身就存在数字 1,这里还需要特判,如果存在,只要将剩下的数全变为 1 就行了。

来说一下我赛时犯的错误吧,我其实特判都想到了,把特判 1 打成特判 0 了,千万不要和我犯一样的错误啊。我真是个唐必。

代码?自己想。。。

好吧,贴一下。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],s[35][N];
int main(){
	int n;cin>>n;int cnt=0;
	int gcd=a[1];
	for(int i=1;i<=n;i++){
		cin>>a[i];
		cnt+=(a[i]==1);
		gcd=__gcd(gcd,a[i]);
	}
	if(cnt){
        cout<<n-cnt;
		return 0;
	}
	if(gcd>1){
        cout<<"-1";
		return 0;
	}
	for(int i=1;i<=n;i++)s[0][i]=a[i];
	for(int i=1;i<=log2(n);i++){
		for(int j=1;j<=n-(1<<i)+1;j++){
			s[i][j]=__gcd(s[i-1][j],s[i-1][j+(1<<(i-1))]);
		}
	}
	for(int ln=2;ln<=n;ln++){
		for(int l=1;l+ln-1<=n;l++){
			int r=l+ln-1;
			int len=log2(r-l+1);
			if(__gcd(s[len][l],s[len][r-(1<<len)+1])==1){
				cout<<r-l+n-1;
				return 0;
			}
		}
	}
} 
posted @ 2026-10-17 14:24  SCX2014  阅读(6)  评论(0)    收藏  举报