zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

      题目传送门

    MRO-Ant colony

    题目描述

    The ants are scavenging an abandoned ant hill in search of food.

    The ant hill has nn chambers and n-1n1 corridors connecting them.

    We know that each chamber can be reached via a unique path from every other chamber.

    In other words, the chambers and the corridors form a tree.

    There is an entrance to the ant hill in every chamber with only one corridor leading into (or out of) it.

    At each entry, there are gg groups of m_1,m_2,cdots,m_gm1,m2,,mg ants respectively.

    These groups will enter the ant hill one after another, each successive group entering once there are no ants inside.

    Inside the hill, the ants explore it in the following way:

    • Upon entering a chamber with dd outgoing corridors yet unexplored by the group,the group divides into ddgroups of equal size. Each newly created group follows one of the d corridors.If d=0d=0, then the group exits the ant hill.

    • If the ants cannot divide into equal groups, then the stronger ants eat the weaker until a perfect division is possible.Note that such a division is always possible since eventually the number of ants drops down to zero.Nothing can stop the ants from allowing divisibility - in particular, an ant can eat itself, and the last one remaining will do so if the group is smaller than dd.

    The following figure depicts mm ants upon entering a chamber with three outgoing unexplored corridors, dividing themselves into three (equal) groups of left lfloor m/3 ight floorm/3⌋ ants each.

    A hungry anteater dug into one of the corridors and can now eat all the ants passing through it.

    However, just like the ants, the anteater is very picky when it comes to numbers.

    It will devour a passing group if and only if it consists of exactly kk ants.

    We want to know how many ants the anteater will eat.

    给一棵树,对于每个叶子节点,都有g群蚂蚁要从外面进来,每群蚂蚁在行进过程中只要碰到岔路,就将平均地分成岔路口数-1那么多份,然后平均地走向剩下的那些岔路口,余下的蚂蚁自动消失,树上有一个关键边,假如有一群蚂蚁通过了这条边且数量恰好为k,这k只蚂蚁就被吃掉,问一共有多少只蚂蚁被吃掉

    输入输出格式

    输入格式:

     

    The first line of the standard input contains three integers nn, gg, kk(2le n,gle 1 000 0002n,g1 000 000, 1le kle 10^91k109), separated by single spaces.

    These specify the number of chambers, the number of ant groups and the number of ants the anteater devours at once. The chambers are numbered from 1 to nn.

    The second line contains gg integers m_1,m_2,cdots,m_gm1,m2,,mg (1le m_ile 10^91mi109), separated by single spaces, where m_imi gives the number of ants in the ii-th group at every entrance to the ant hill. The n-1n1 lines that follow describe the corridors within the ant hill;the ii-th such line contains two integers a_iai,b_ibi (1le a_i,b_ile n1ai,bin), separated by a single space, that indicate that the chambers no. a_iai and b_ibi are linked by a corridor. The anteater has dug into the corridor that appears first on input.

     

    输出格式:

     

    Your program should print to the standard output a single line containing a single integer: the number of ants eaten by the anteater.

     

    输入输出样例

    输入样例#1: 
    7 5 3
    3 4 1 9 11
    1 2
    1 4
    4 3
    4 5
    4 6
    6 7
    
    输出样例#1: 
    21
    

    说明

    给一棵树,对于每个叶子节点,都有g群蚂蚁要从外面进来,每群蚂蚁在行进过程中只要碰到岔路,就将平均地分成岔路口数-1那么多份,然后平均地走向剩下的那些岔路口,余下的蚂蚁自动消失,树上有一个关键边,假如有一群蚂蚁通过了这条边且数量恰好为k,这k只蚂蚁就被吃掉,问一共有多少只蚂蚁被吃掉


      分析:

      一道比较考思维的题。

      如果按照题目的要求从叶子节点开始做的话,很难有比较优秀的方法。

      那么就换一种方式,从两个给定的根开始。因为给定的一条边一定会把一棵树分割成两部分,所以我们可以直接把这棵树当作两棵树来处理。对于每一棵树,从根节点开始$DFS$,确定从这个点到达根节点时如果要正好有$k$只蚂蚁,在这个点至少需要多少蚂蚁,至多能有多少蚂蚁。再对给定的每一群蚂蚁排序。处理完以后,对于所有的叶子节点二分答案找到每个叶子节点有多少群蚂蚁合法,最后输出答案就行了。

      讲的比较抽象,可以看代码理解。

      Code:

    //It is made by HolseLee on 5th Nov 2018
    //Luogu.org P3576
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N=1e6+7;
    int n,g,k,head[N],cnte,dg[N],fa[N],sx,sy;
    ll ans,maxn[N],minn[N],c[N];
    struct Edge { int to,nxt; }e[N<<1];
    
    inline int read()
    {
        char ch=getchar(); int x=0; bool flag=false;
        while( ch<'0' || ch>'9' ) {
            if( ch=='-' ) flag=true; ch=getchar();
        }
        while( ch>='0' && ch<='9' ) {
            x=x*10+ch-'0'; ch=getchar();
        }
        return flag ? -x : x;
    }
    
    inline void add(int x,int y)
    {
        e[++cnte].to=y, e[cnte].nxt=head[x], head[x]=cnte;
        e[++cnte].to=x, e[cnte].nxt=head[y], head[y]=cnte;
    }
    
    void dfs(int x)
    {
        for(int i=head[x]; i; i=e[i].nxt) {
            if( e[i].to!=fa[x] ) {
                fa[e[i].to]=x; dg[x]++;
            }
        }
        for(int i=head[x],y; i; i=e[i].nxt) {
            y=e[i].to;
            if( y==fa[x] ) continue;
            minn[y]=minn[x]*dg[x];
            maxn[y]=(maxn[x]+1)*dg[x]-1;
            maxn[y]=min(maxn[y],c[g]);
            if( minn[y]<=c[g] ) dfs(y);
        }
    }
    
    inline ll getans(ll x)
    {
        int l=0,r=g,mid,ret=0;
        while( l<=r ) {
            mid=(l+r)>>1;
            if( c[mid]<x ) l=mid+1,ret=mid;
            else r=mid-1;
        }
        return ret;
    }
    
    int main()
    {
        n=read(), g=read(), k=read();
        for(int i=1; i<=g; ++i) c[i]=read();
        sort(c+1,c+g+1);
        int x,y; sx=read(), sy=read();
        for(int i=2; i<n; ++i) {
            x=read(), y=read(); add(x,y);
        }
        maxn[sx]=maxn[sy]=minn[sx]=minn[sy]=k;
        dfs(sx);dfs(sy);
        for(int i=1; i<=n; ++i)
        if( !dg[i] ) ans+=getans(maxn[i]+1)-getans(minn[i]);
        printf("%lld
    ",ans*k);
        return 0;
    }
  • 相关阅读:
    如何开发优秀的HTML5游戏?迪斯尼《寻找奥兹之路》游戏技术详解(一)
    C++ Prime学习过程中的细节摘记(三)
    android学习笔记53_采用网页设计软件界面,以及使用android系统内置的浏览器,利用js调用java方法
    黑马韩前成linux从入门到精通の轻松搞定负载均衡
    thinkphp一键清除缓存的方法
    使用treeNMS管理及监控Redis
    ThinkPHP 的缓存大概多久更新一次
    redis查数据
    redis可视化客户端工具TreeNMS
    MeeGo开发进程通信核心 DBus调试工具 狼人:
  • 原文地址:https://www.cnblogs.com/cytus/p/9910162.html
Copyright © 2011-2022 走看看