zoukankan      html  css  js  c++  java
  • F

    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
    ", 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;
    }
    
  • 相关阅读:
    做人做事
    不骄不躁
    争取
    收入
    Windows 7下的Comodo Firewall免费防火墙
    成功水平
    成家立业
    Windows无法安装到GPT格式磁盘的根本解决办法
    安装Windows10操作系统
    安装操作系统的几种方式
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13769895.html
Copyright © 2011-2022 走看看