zoukankan      html  css  js  c++  java
  • [Usaco 2012 Feb]Nearby Cows

    题目描述

    FJ发现他的牛经常跑到附近的草地去吃草,FJ准备给每个草地种足够的草供这个草地以及附近草地的奶牛来吃。FJ有N个草地(1<=N<=100000),有N-1条双向道路连接这些草地,FJ精心设计了这些道路使每两个草地有且仅有一条简单路径连接。第i个草场有Ci头牛,有时候奶牛会走过K条道路到其他草地吃草。FJ想知道每个草场最多可能有的奶牛数量Mi,即所有走过K条道路后可能到达i的奶牛总数。

    输入格式

    Line 1: Two space-separated integers, N and K.

    Lines 2..N: Each line contains two space-separated integers, i and j (1 <= i,j <= N) indicating that fields i and j are directly connected by a trail.

    Lines N+1..2N:

    Line N+i contains the integer C(i). (0 <= C(i) <= 1000)

    输出格式

    Lines 1..N: Line i should contain the value of M(i).


    如果我们设dp(x)表示最多走k条路可以到达x的奶牛数,那么我们就不知道这dp(x)头奶牛里面多少是刚好走了k条路的,就不能更新相连的节点。我们唯一的更新dp数组的方法就是暴力往上走k步然后往下走k步。最坏的情况时间复杂度为O(N^2)——如果直径长度小于等于k的话。一般情况大概是O(NK * ∑degree[i]),很好卡的(其中degree表示节点的度数)。

    考虑改变状态。既然我们需要知道有多少奶牛走了k步刚好走到x甚至更多的信息,我们不妨扩展一下状态:

    设dp(i,j)表示刚好走了j步到达i节点的奶牛个数。由于整个图是一棵树,显然答案具有传递性。具体为:走d步到达x点的奶牛个数=走d-1步到达 ( 走1步到达x节点的 ) 节点的奶牛个数之和。那么答案就分成了两部分:一部分为当前子树中走过来的奶牛个数,另一部分为除了当前子树之外的点中走过来的奶牛个数。

    设val(u)表示节点u原有的奶牛个数,并且设u有q个儿子。

    先考虑第一种,那么可以写出状态转移方程:

    [dp[u][i]=sum_{j=1}^{q}dp[son[j]][i-1]; ]

    其中1≤i≤k。初始化dp(u,0)=val(u)。

    再考虑第二种。先写出大概的方程:

    [dp[son[x]][i]=dp[u][i-1]; ]

    然而经过细心观察(或者直接提交)发现,这个方程是错的!为什么呢?因为dp(u,i-1)中显然有dp(son(x),i-2)的部分,然而这dp(son(x),i-2)头奶牛显然与son(x)的距离为1,而上面的方程显然把这个距离算成了3。由于我们在第一个方程中就已经计算了这一部分,所以我们考虑把这一部分给去掉。那么修改状态转移方程:

    [dp[son[x]][i]=dp[u][i-1]-dp[son[x]][i-2] ]

    然而经过细心观察(或者直接提交)发现,这个方程还是错的!为什么呢?其实是一个小细节,当i=1时后面那一坨是没有意义的。一是因为可能造成RE,二是跟son(x)距离为1的son(x)的子节点不能走i-1步到达u。特判一下即可。

    * 代码中用m代替了k(个人习惯)

    * 不开long long见祖宗

    时间复杂度为O(NK)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 100001
    #define maxm 21
    using namespace std;
     
    struct edge{
        int to,next;
        edge(){}
        edge(const int &_to,const int &_next){ to=_to,next=_next; }
    }e[maxn<<1];
    int head[maxn],k;
     
    long long dp[maxn][maxm];
    int n,m,val[maxn];
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }
     
    void dfs1(int u,int pre){
        dp[u][0]=val[u];
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v==pre) continue;
            dfs1(v,u);
            for(register int i=1;i<=m;i++) dp[u][i]+=dp[v][i-1];
        }
    }
     
    void dfs2(int u,int pre){
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v==pre) continue;
            for(register int i=m;i>=1;i--) dp[v][i]+=dp[u][i-1]-(i==1?0:dp[v][i-2]);
            dfs2(v,u);
        }
    }
     
    int main(){
        memset(head,-1,sizeof head);
        n=read(),m=read();
        for(register int i=1;i<n;i++){
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        for(register int i=1;i<=n;i++) val[i]=read();
     
        dfs1(1,0),dfs2(1,0);
        for(register int i=1;i<=n;i++){
            long long sum=0;
            for(register int j=0;j<=m;j++) sum+=dp[i][j];
            printf("%lld
    ",sum);
        }
        return 0;
    }
    
  • 相关阅读:
    ARMV8 datasheet学习笔记3:AArch64应用级体系结构之Memory order
    ARMV8 datasheet学习笔记3:AArch64应用级体系结构之Atomicity
    ARMV8 datasheet学习笔记3:AArch64应用级体系结构
    ARMV8 datasheet学习笔记2:概述
    最短路径
    网络流
    二分图
    zabbix 3.4新功能值预处理
    zabbix 3.4新功能值解析——Preprocessing预处理
    Zabbix监控windows的CPU利用率和其他资源
  • 原文地址:https://www.cnblogs.com/akura/p/10914092.html
Copyright © 2011-2022 走看看