当找到一个根的时候会把区间分成两个部分,然后递归做
问题就是怎么找根了
可以用bzoj4059那种思路,大概叫启发式分裂吧
对每个数,可以预处理一下在它左边第一个与他不互质的数和在它右边第一个与它不互质的数
然后就 O(nlogn) O ( n log n ) 搞就可以了
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1000010;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int n,mx,a[N],p[N*10],f[N*10],b[N],c[N],lst[N*10],fa[N];
inline void Pre(const int &n){
for(int i=2;i<=n;i++){
if(!p[i]) p[++*p]=i,f[i]=i;
for(int j=1;j<=*p && 1LL*p[j]*i<=n;j++){
p[p[j]*i]=1; f[p[j]*i]=p[j];
if(i%p[j]==0) break;
}
}
}
bool solve(int l,int r,int p){
if(l>r) return true;
int L=l,R=r;
while(L<=R){
if(b[L]<l && c[L]>r){
fa[L]=p; return solve(l,L-1,L) && solve(L+1,r,L);
}
if(b[R]<l && c[R]>r){
fa[R]=p; return solve(l,R-1,R) && solve(R+1,r,R);
}
L++; R--;
}
return false;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
read(n);
for(int i=1;i<=n;i++)
read(a[i]),mx=max(mx,a[i]);
Pre(mx);
for(int i=1;i<=n;i++){
int cur=a[i],cans=0;
while(cur^1){
int g=f[cur];
cans=max(cans,lst[g]);
lst[g]=i;
while(cur%g==0) cur/=g;
}
b[i]=cans;
}
for(int i=1;i<=mx;i++) lst[i]=n+1;
for(int i=n;i;i--){
int cur=a[i],cans=n+1;
while(cur^1){
int g=f[cur];
cans=min(cans,lst[g]);
lst[g]=i;
while(cur%g==0) cur/=g;
}
c[i]=cans;
}
if(solve(1,n,0))
for(int i=1;i<=n;i++) printf("%d%c",fa[i],i==n?'\n':' ');
else
puts("impossible");
return 0;
}