题目大意
有一个长度为 n n n的序列 a a a,你每次可以选择 gcd \gcd gcd不为一的两个数 a i a_i ai和 a i + 1 a_{i+1} ai+1,将两个数合并,其值为两个数的 lcm \text{lcm} lcm,也就是删去 a i + 1 a_{i+1} ai+1,再让 a i = lcm ( a i , a i + 1 ) a_i=\text{lcm}(a_i,a_{i+1}) ai=lcm(ai,ai+1)。
求是否可以进行若干次操作,使得序列 a a a的长度变为 1 1 1。如果可行,就输出 Y e s Yes Yes;否则,输出 N o No No。
1 ≤ n ≤ 1 0 5 , 1 ≤ a i ≤ 700 1\leq n\leq 10^5,1\leq a_i\leq 700 1≤n≤105,1≤ai≤700
题解
首先,我们要知道,能合并的就合并,并不存在合并一个会使其他原本能合并的变得不能合并。我们可以维护一个栈,枚举每个元素,将当前元素与栈顶元素求 gcd \gcd gcd,如果 gcd \gcd gcd不为 1 1 1就取出栈顶元素并与当前元素合并,并继续判断接下来的栈顶元素与当前元素的 gcd \gcd gcd是否为 1 1 1,直到不为一或栈为空。最后看栈内元素是否为 1 1 1即可。
但在合并的过程中 a i a_i ai会很大,甚至连 i n t 128 int128 int128都可能存不下。而 700 700 700以内的质数只有 125 125 125个,我们可以用 b i t s e t bitset bitset来存 a i a_i ai有哪些质因子。
虽然用了 b i t s e t bitset bitset,但还是要枚举每个 a i a_i ai是否有每个质因数,所以时间复杂度为 O ( n p ) O(np) O(np),其中 p p p为 700 700 700以内质数的个数,也就是 125 125 125。
code
#include<bits/stdc++.h>
using namespace std;
const int N=700;
int n,q1,a[100005],r[100005],z[705],p[705],q[100005];
bitset<130>v[100005];
void init(){for(int i=2;i<=N;i++){if(!z[i]) p[++p[0]]=i;for(int j=1;j<=p[0]&&i*p[j]<=N;j++){z[i*p[j]]=1;if(i%p[j]==0) break;}}
}
int main()
{init();scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);for(int j=1;a[i]>1&&j<=p[0];j++){if(a[i]%p[j]==0) v[i][j-1]=1;while(a[i]%p[j]==0) a[i]/=p[j];}}for(int i=1;i<=n;i++){q[++q1]=i;while(q1>=2&&(v[q[q1]]&v[q[q1-1]]).count()){v[q[q1-1]]|=v[q[q1]];--q1;}}if(q1==1) printf("Yes");else printf("No");return 0;
}