zoukankan      html  css  js  c++  java
  • CSU 1804

    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804

    Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
    为了方便,点用 1,2,…,n 编号。 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0),Bobo 想知道
     
     
    除以 (10 9+7) 的余数。
    其中,a i,b j 是给定的数列。
     

    Input

    输入包含不超过 15 组数据。
    每组数据的第一行包含两个整数 n,m (1≤n,m≤10 5).
    接下来 n 行的第 i 行包含两个整数 a i,b i (0≤a i,b i≤10 9).
    最后 m 行的第 i 行包含两个整数 u i,v i,代表一条从点 u i 到 v i 的边 (1≤u i,vi≤n)。
     

    Output对于每组数据,输出一个整数表示要求的值。Sample Input

    3 3
    1 1
    1 1
    1 1
    1 2
    1 3
    2 3
    2 2
    1 0
    0 2
    1 2
    1 2
    2 1
    500000000 0
    0 500000000
    1 2
    

    Sample Output

    4
    4
    250000014

    题解:

    首先,假如我们计算$sumlimits_{i = 1}^n {sumlimits_{j = 1}^n {left( {countleft( {i,j} ight) imes a_i imes b_j } ight)} } $

    这个的时候,固定一个点i,枚举j进行计算的话,就有:

    $a_i imes left[ {sumlimits_{j = 1}^n {left( {countleft( {i,j} ight) imes b_j } ight)} } ight]$

    我们不妨设$dpleft[ i ight] = sumlimits_{j = 1}^n {left( {countleft( {i,j} ight) imes b_j } ight)} $

    那么,最后的${ m{ans}} = sumlimits_{i = 1}^n {left{ {a_i imes left[ {sumlimits_{j = 1}^n {left( {countleft( {i,j} ight) imes b_j } ight)} } ight]} ight}} $ 

    问题来了,状态转移方程是什么?

    假设对于点i,它有K个子节点,就有:

    $dpleft[ i ight] = sumlimits_{k = 1}^K {left( {b_k + dpleft[ k ight]} ight)} $

    (根据题意无环图,则存在 Edge(i→k) 就一定不存在一条路径从k点到i点,所以计算dp[k]时就一定不会涉及到dp[i])

    另外,本题如果不是有向无环图而是一棵树的话,很显然,直接从树根往下dfs计算每个节点i的dp[i]即可,

    但是现在有向无环图,可能出现如下情况:

    这样一来,如果主函数里单单dfs(1)或者单单dfs(2)都不能把整个图上所有节点的dp[i]都计算到,

    因此要把所有in-degree[i]==0的节点i都dfs(i).

    AC代码:

    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    typedef long long LL;
    
    const LL MOD=1e9+7;
    const int maxn=1e5+10;
    
    int n,m;
    int indegree[maxn];
    LL a[maxn],b[maxn];
    LL dp[maxn];
    
    struct Edge{
        int u,v;
        Edge(int u,int v){this->u=u,this->v=v;}
    };
    vector<Edge> E;
    vector<int> G[maxn];
    void init(int l,int r)
    {
        E.clear();
        for(int i=l;i<=r;i++) G[i].clear();
    }
    void addedge(int u,int v)
    {
        E.push_back(Edge(u,v));
        G[u].push_back(E.size()-1);
    }
    
    LL dfs(int u)
    {
        if(dp[u]!=-1) return dp[u];
    
        dp[u]=0;
        for(int i=0,_size=G[u].size();i<_size;i++)
        {
            Edge &e=E[G[u][i]]; int v=e.v;
            dp[u]=(dp[u]+b[v]+dfs(v))%MOD;
        }
        return dp[u];
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
    
            init(1,n); //邻接表初始化
            memset(indegree,0,sizeof(indegree));
            for(int i=1,u,v;i<=m;i++)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
                indegree[v]++;
            }
    
            memset(dp,-1,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                if(indegree[i]==0) dfs(i);
            }
    
            LL ans=0;
            for(int i=1;i<=n;i++) ans = ( ans + (dp[i]*a[i]) % MOD ) % MOD;
    
            printf("%lld
    ",ans);
        }
    }
  • 相关阅读:
    hdu1698(线段树)
    poj3468(线段树)
    hdu1394(线段树求逆序对)
    hdu1754(线段树)
    hdu1166(线段树)
    hdu2412(树形dp)
    hdu4714(树形dp)
    hdu4705(树形dp)
    hdu4679(树形dp)
    滑动导航条
  • 原文地址:https://www.cnblogs.com/dilthey/p/8983122.html
Copyright © 2011-2022 走看看