F - Factor-Free Tree 遞迴
阿新 • • 發佈:2020-10-05
題目大意:
給出某一顆帶點權樹的中序遍歷序列,問是否存在一顆對應的帶點權樹滿足條件:每個節點的子孫節點的權值都和該節點的權值互質。如果存在則輸出符合條件的樹的每個節點父親節點。
題解:
這個題目其實還是很簡單的,但是不知道為什麼出的人這麼少,很可能是複雜度沒算對,還有就是一些小技巧沒有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; }