F - Factor-Free Tree 递归

F - Factor-Free Tree 递归

题目大意:

给出某一颗带点权树的中序遍历序列,问是否存在一颗对应的带点权树满足条件:每个节点的子孙节点的权值都和该节点的权值互质。如果存在则输出符合条件的树的每个节点父亲节点。

题解:

这个题目其实还是很简单的,但是不知道为什么出的人这么少,很可能是复杂度没算对,还有就是一些小技巧没有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\n", 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\n", x,i,vis[i]);
        }
    }
    if(now>1){
        int pos = lower_bound(isp,isp+cnt,now)-isp;
        // printf("pos = %d x = %d now = %d\n", pos,x,now);
        rc[x] = min(rc[x],vis[pos]);
        vis[pos] = x;
    }
    // printf("rc[%d]=%d\n", x,rc[x]);
}
int ans[maxn];
bool dfs(int id,int l,int r){
    // printf("id = %d l = %d r = %d\n", 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\n", 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\n", 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("\n");
    }
    else printf("impossible\n");
    return 0;
}
posted @ 2020-10-05 14:20  EchoZQN  阅读(244)  评论(0编辑  收藏  举报