1. 程式人生 > 實用技巧 >F - Factor-Free Tree 遞迴

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