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;
}
}
}
}

浙公网安备 33010602011771号