题目大意:
给出某一颗带点权树的中序遍历序列,问是否存在一颗对应的带点权树满足条件:每个节点的子孙节点的权值都和该节点的权值互质。如果存在则输出符合条件的树的每个节点父亲节点。
题解:
这个题目其实还是很简单的,但是不知道为什么出的人这么少,很可能是复杂度没算对,还有就是一些小技巧没有get。
lc[i] 表示对于第 i 个数,左边离它最近的和他 gcd>1 的数的位置,rc[i] 表示对于第 i 个数,右边离它最近和他 gcd > 1 的数的位置,这个可以直接暴力求。
然后就是一个递归的过程,但是这个复杂度有点麻烦,既不能从左往右,又不能从右往左,但是同时从左往右和从右往左是可以的,因为在两边的话,可以很快找到,在中间的话,会减少递归的层数。
所以最后的复杂度就是 nlogn,这个算是这个题目最难的地方吧。。。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e7+10;
const int maxm = 1e6+10;
int isp[maxn],cnt,v[maxn];
void init() {
cnt = 0;
memset(v,0,sizeof(v));
for (int i = 2; i < maxn; ++i) {
if (!v[i]) {
v[i] = i;
isp[cnt++] = i;
}
for (int j = 0; j < cnt; ++j) {
if (1ll * i * isp[j] >= maxn) break;
v[i * isp[j]] = isp[j];
}
}
}
int vis[maxm],lc[maxm],rc[maxm],a[maxn];
void judge1(int x){
int sq = sqrt(a[x]);
int m = upper_bound(isp,isp+cnt,sq)-isp;
int now = a[x];
for(int i=0;i<m;i++){
if(now%isp[i]==0){
lc[x] = max(lc[x],vis[i]),vis[i] = x;
while(now%isp[i]==0) now/=isp[i];
}
}
if(now>1){
int pos = lower_bound(isp,isp+cnt,now)-isp;
lc[x] = max(lc[x],vis[pos]);
vis[pos] = x;
}
// printf("lc[%d]=%d
", x,lc[x]);
}
void judge2(int x){
int sq = sqrt(a[x]);
int m = upper_bound(isp,isp+cnt,sq)-isp;
int now = a[x];
for(int i=0;i<m;i++){
if(now%isp[i]==0){
rc[x] = min(rc[x],vis[i]),vis[i] = x;
while(now%isp[i]==0) now/=isp[i];
// printf("x = %d i = %d vis=%d
", x,i,vis[i]);
}
}
if(now>1){
int pos = lower_bound(isp,isp+cnt,now)-isp;
// printf("pos = %d x = %d now = %d
", pos,x,now);
rc[x] = min(rc[x],vis[pos]);
vis[pos] = x;
}
// printf("rc[%d]=%d
", x,rc[x]);
}
int ans[maxn];
bool dfs(int id,int l,int r){
// printf("id = %d l = %d r = %d
", id,l,r);
if(l>r) return true;
if(r-l+1==1){
ans[l] = id;
return true;
}
for(int i=l,j=r;i<=j;i++,j--){
// printf("i = %d lc[%d]=%d rc[%d]=%d
", i,i,lc[i],i,rc[i]);
if(lc[i]<l&&rc[i]>r){
ans[i] = id;
int f1 = dfs(i,l,i-1);
int f2 = dfs(i,i+1,r);
if(!f1||!f2) return false;
return true;
}
// printf("j = %d lc[%d]=%d rc[%d]=%d
", j,j,lc[j],j,rc[j]);
if(lc[j]<l&&rc[j]>r){
ans[j] = id;
int f1 = dfs(j,l,j-1);
int f2 = dfs(j,j+1,r);
if(!f1||!f2) return false;
return true;
}
}
return false;
}
int main(){
init();
int n;
scanf("%d",&n);
memset(vis,-1,sizeof(vis));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
judge1(i);
}
memset(rc,inf,sizeof(rc));
memset(vis,inf,sizeof(vis));
for(int i=n;i>=1;i--) judge2(i);
int flag = dfs(0,1,n);
if(flag){
for(int i=1;i<=n;i++) printf("%d ", ans[i]);
printf("
");
}
else printf("impossible
");
return 0;
}