zoukankan      html  css  js  c++  java
  • Apple Tree

    题意:

    给一有根树,每个叶子上有一些苹果,现在要求你拿掉一些苹果,使得每一个点的 儿子的子树内的苹果数相同。

    解法:

    首先可以发现$cnt$个叶子节点之间的关系可以用$cnt-1$个独立方程表示出来。

    这样相当于在方程的解中只有一个变元。

    接下来求出最小整数基底:这个我们可以两遍$dfs$ + $gcd$求出。

    总效率$O(nlogn)$

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    #define LL long long
    #define N 100010
    #define INF 0x3f3f3f3f3f3f3f3fLL
    
    using namespace std;
    
    struct edge
    {
        int x,to;
    }E[N<<1];
    
    int n,totE;
    int g[N];
    LL f[N],a[N],sum;
    bool is_leaf[N];
    
    void addedge(int x,int y)
    {
        E[++totE] = (edge){y,g[x]}; g[x]=totE;
        E[++totE] = (edge){x,g[y]}; g[y]=totE;
    }
    
    LL gcd(LL a,LL b)
    {
        if(!b) return a;
        return gcd(b,a%b);
    }
    
    #define p E[i].x
    
    LL calc(int x,int tp)
    {
        int cnt=0;
        LL ans=1;
        for(int i=g[x];i;i=E[i].to)
            if(p!=tp)
            {
                LL tmp = calc(p,x);
                cnt++;
                if(ans/gcd(ans,tmp)<=sum/tmp)
                    ans = ans/gcd(ans,tmp)*tmp;
                else return -1;
            }
        if(!cnt)
        {
            is_leaf[x]=1;
            return 1LL;
        }
        if(ans<=sum/cnt) return ans*(LL)cnt;
        else return -1;
    }
    
    void dfs(int x,int tp)
    {
        int cnt=0;
        for(int i=g[x];i;i=E[i].to)
            if(p!=tp) cnt++;
        for(int i=g[x];i;i=E[i].to)
            if(p!=tp)
            {
                f[p]=f[x]/(LL)cnt;
                dfs(p,x);
            }
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            for(int i=1;i<=n;i++) g[i]=0,is_leaf[i]=0;
            totE=0;
            sum=0;
            for(int i=1;i<=n;i++)
                scanf("%I64d",&a[i]),sum+=a[i];
            for(int i=1,x,y;i<n;i++)
            {
                scanf("%d%d",&x,&y);
                addedge(x,y);
            }
            f[1]=calc(1,1);
            if(f[1]==-1)
            {
                cout << sum << endl;
                continue;
            }
            dfs(1,1);
            LL t=INF, ans=0;
            for(int i=1;i<=n;i++)
                if(is_leaf[i])
                {
                    ans += a[i];
                    t = min(t, a[i]/f[i]);
                }
            ans -= t*f[1];
            cout << ans << endl;
        }
        return 0;
    }
    
    
    /*
    t*A_i <= B_i(原先的) 
    t <= B_i/A_i
    */
    View Code
  • 相关阅读:
    项目架构开发:数据访问层之Cache
    微信公众号平台接口开发:菜单管理
    【软件工程】第0次个人作业
    OO第四次博客作业
    OO第三次博客作业
    OO第二次博客作业
    Java学习笔记
    SQLInjection 靶场配置
    OO第一次博客作业
    面向对象先修:Java入门
  • 原文地址:https://www.cnblogs.com/lawyer/p/6646785.html
Copyright © 2011-2022 走看看