zoukankan      html  css  js  c++  java
  • BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash

    BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash

    题意:

    给你一棵树每个点有一个权值,要求修改最少的权值,使得每个节点的权值等于其儿子的权值和且儿子的权值都相等。

    分析:

    首先我们发现在树中如果确定一个点的权值,那么整颗树的方案就能够确定

    问题转化成求哪个方案包含的点最多

    如何求包含这个点的是哪个方案?

    可以给每个点分配一个新的权值

    不妨假设1号点的权值不变

    1号点的儿子的权值为原来的权值乘上1号点儿子的个数.......以此类推。

    发现权值相同的点在一个方案里

    由于权值可能很大,我们随缘取模哈希一下就行

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define LL long long
    #define N 500050
    int head[N],to[N<<1],nxt[N<<1],val[N],cnt;
    int n,son[N],dep[N];
    LL now[N];
    int h[1930010],p=1910009;
    int ans,key[1930010];
    inline void add(int u,int v)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    void insert(LL x)
    {
        int k=(x%p+p)%p;
        while(h[k]&&key[k]!=x)
        {
            k++;
        }
        h[k]++;key[k]=x;
        ans=max(ans,h[k]);
    }
    void dfs(int x,int y)
    {
        int i;
        for(i=head[x];i;i=nxt[i])
        {
            if(to[i]!=y)
            {
                son[x]++;
            }
        }
        for(i=head[x];i;i=nxt[i])
        {
            if(to[i]!=y)
            {
                now[to[i]]=now[x]*son[x]%p;
                insert(val[to[i]]*now[to[i]]%p);
                dfs(to[i],x);
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        int i,x,y;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
        }
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        insert(val[1]);
        now[1]=1;
        dfs(1,0);
        printf("%d
    ",n-ans);
    }
    

      

     

  • 相关阅读:
    Java1:Chapter2
    Java1:Chapter1
    Java1:Chapter11
    Java1:Chapter8
    Java1:Chapter6
    Android day 03
    Android day02
    Android day01
    二进制文件的读写
    字符流
  • 原文地址:https://www.cnblogs.com/suika/p/8551682.html
Copyright © 2011-2022 走看看