• 1481F.AB Tree(树上信息统计+01背包+记录DP路径+Bitset优化时间复杂度)


     题意:

    给出一棵树,根节点为1。你可以给x个点赋值A,剩下n-x个点赋值B。询问从根节点到每个点的路径构成的字符串的最小集合。

    题解:

    结论1:每一层的点赋相同的值,可以使答案最优。

    所以可以把每一层看成物品,物品的价值就是这一层的点数,跑一个01背包。

    如果存在一组物品使得它们的和恰好为x,那么就直接输出层数即可。

    如果不存在,最多也只会是层数+1。

    结论2:对单层修改叶子节点的值,对答案的影响最小。

    先找到叶子节点最多的那一层,试图通过改这一层的叶子节点的状态来弥补DP状态。

    结果T15。

    这是TLE的代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+100;
    int n,x;
    vector<int> g[maxn];
    vector<int> d[maxn];
    int cnt[maxn];
    int m;
    void dfs (int x,int f,int dep) {
        m=max(m,dep);
        d[dep].push_back(x);
        if (g[x].size()==1) cnt[dep]++;
        for (int y:g[x]) {
            if (y==f) continue;
            dfs(y,x,dep+1);
        }
    }
    map<int,int> f[maxn];
    int ans[maxn];
    int ff=0;
    int main () {
        scanf("%d%d",&n,&x);
        if (x>n-x) x=n-x,ff=1; 
        for (int i=2;i<=n;i++) {
            int y;
            scanf("%d",&y);
            g[i].push_back(y);
            g[y].push_back(i);
        }
        dfs(1,0,1);
        //for (int i=1;i<=m;i++) printf("%d ",d[i].size());
        //rintf("
    ");
        f[0][0]=1;
        for (int i=1;i<=m;i++) {
            for (int j=x;j>=0;j--) f[i][j]|=f[i-1][j];
            for (int j=x;j>=d[i].size();j--) {
                f[i][j]|=f[i-1][j-d[i].size()];
            }
        }
        if (f[m][x]) {
            printf("%d
    ",m);
            for (int i=m;i>=1;i--) {
                if (d[i].size()<=x&&f[i-1][x-d[i].size()]) {
                    x-=d[i].size();
                    for (int v:d[i]) ans[v]=1;
                }
            }
            if (!ff)
                for (int i=1;i<=n;i++) if (ans[i]==1) printf("a");else printf("b");
            else
                for (int i=1;i<=n;i++) if (ans[i]==1) printf("b");else printf("a");
        }
        else {
            printf("%d
    ",m+1);
            for (int i=0;i<=m;i++) f[i].clear();
            f[0][0]=1;
            int Max=0,u=-1;
            for (int i=1;i<=m;i++) if (cnt[i]>Max) {
                Max=cnt[i];
                u=i;
            }
            for (int i=1;i<=m;i++) {
                for (int j=x;j>=0;j--) f[i][j]|=f[i-1][j];
                if (i==u) continue;
                for (int j=x;j>=d[i].size();j--) {
                    f[i][j]|=f[i-1][j-d[i].size()];
                }
            } 
            int ed=-1;
            for (int i=0;i<x;i++) {
                if (f[m][i]&&i+Max>=x) {
                    ed=i;
                    break;
                }
            }
            int tt=x-ed;
            for (int v:d[u]) {
                if (g[v].size()>1) continue;
                if (!tt) break;
                tt--;
                ans[v]=1;
            }
            for (int i=m;i>=1;i--) {
                if (i==u) continue;
                if (d[i].size()<=ed&&f[i-1][ed-d[i].size()]) {
                    ed-=d[i].size();
                    for (int v:d[i]) ans[v]=1;
                }
            }
            if (!ff)
                for (int i=1;i<=n;i++) if (ans[i]==1) printf("a");else printf("b");
            else
                for (int i=1;i<=n;i++) if (ans[i]==1) printf("b");else printf("a");
        }
    }
    View Code

    看了别人的题解才明白,这里需要套一个Bitset优化背包求解的过程。对比原来的代码理解一下吧。。。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+100;
    const int inf=1e9;
    int n,m,x;
    int dep[maxn];//节点在第几层 
    int num[maxn];//每一层的节点个数
    int lev[maxn];//每一层的叶子节点个数
    bitset<maxn> f[2500];
    int w[maxn];
    int ok[maxn];
    vector<int> g[maxn],v[maxn];
    unordered_map<int,int> vis;
    void dfs1 (int x,int pre) {
        dep[x]=dep[pre]+1;
        num[dep[x]]++;
        m=max(m,dep[x]);
        if (g[x].size()==1) lev[dep[x]]++;
        for (int y:g[x]) {
            if (y==pre) continue;
            dfs1(y,x);
        }
    }
    void dfs2 (int x,int y) {
        //找dp状态
        if (x==0) return;
        for (int i=0;i<v[x].size();i++) {
            if (w[x]>y||f[x-1][y]) break;
            y-=w[x];
            ok[v[x][i]]=1;
        } 
        dfs2(x-1,y);
    }
    int main () {
        scanf("%d%d",&n,&x);
        for (int i=2;i<=n;i++) {
            int y;
            scanf("%d",&y);
            g[i].push_back(y);
            g[y].push_back(i);
        }
        dfs1(1,0);
        int cnt=0;
        for (int i=1;i<=m;i++) {
            //第一步,把相同点数的层合并
       
            if (vis[num[i]]) {
                v[vis[num[i]]].push_back(i); 
            }
            else {
                vis[num[i]]=++cnt;
                w[cnt]=num[i];
                v[cnt].push_back(i);
            }
        }
        f[0][0]=1; 
        for (int i=1;i<=cnt;i++) {
            f[i]=f[i-1]; 
            int sz=v[i].size();
            for (int j=1;j<=sz;j<<=1) {
                sz-=j;
                f[i]|=(f[i]<<(j*w[i]));
            }
            if (sz) f[i]|=f[i]<<(sz*w[i]);//这一步还没懂 
        }
        if (f[cnt][x]) {
            printf("%d
    ",m);
            dfs2(cnt,x);
            for (int i=1;i<=n;i++) {
                if (ok[dep[i]])
                    printf("a");
                else    
                    printf("b");
            }
        }
        else {
            int ans=inf;
            for (int i=x;i>=0;i--) if (f[cnt][i]) {
                ans=i;
                break;
            }
            dfs2(cnt,ans);
            int pp=-1;
            for (int i=1;i<=m;i++) {
                if (!ok[i]&&lev[i]>=x-ans) {
                    pp=i;
                    break;
                }
            }
            printf("%d
    ",m+1);
            for (int i=1;i<=n;i++) {
                if (dep[i]==pp&&g[i].size()==1) {
                    if (ans==x)
                        printf("b");
                    else
                        printf("a"),ans++;
                }
                else {
                    if (ok[dep[i]])
                        printf("a");
                    else
                        printf("b");
                }
            }
        }
    }
     
  • 相关阅读:
    集合框架
    hashtable
    测试3
    opcache的威力
    信息的信息
    php blog to explore
    BEHAT安装
    Failed to start: SocketListener0@0.0.0.0:4444
    模板方法设计模式
    mysqldump
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14395945.html
Copyright © 2020-2023  润新知