zoukankan      html  css  js  c++  java
  • 第十二届湖南省赛 (B

    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
    

    Hint

    思路:

    由有向图拓扑序的性质可以知道,拓扑序在后的节点是没有指向拓扑序在前的节点。

    那么我们在对整个图进行拓扑的时候,把起始点 x 的a[x] 值 附加到 这个边的终点 y 的a[y] 值上。

    并且对于每一个边,我们维护一个 long long 类型的 答案 ans,ans+= a[x]*b[y]  (  边 是 x ~> y )

    那么这里就介绍刚刚我们为什么要附加数值a[x] 到a[y]上。

    如果由三个点  x y z ,由如下的连接关系 x ~> y ~> z 那么x到y的边我们会算一次对答案的贡献值,y到z的边我们也会算一次。

    还有一个x到z的边,我们仍然需要算。因为x可以到达z,那么如果我们在拓扑的时候把a[y]加上a[x] 时, 我们在算 b到z 的边的时候就顺便的加上了a到z的边。

    因为x 的拓扑优先级比y高,并且x可以到达y,那么x就可以到达y能到达的所有边,那么就解释了这样做的原因。

    这样做的时间复杂度就会转化为 O ( N ) 

    主要是理解后就很好写代码,可以自己动手画图理解一下上面 讲的内容。

     

    实现细节见ac代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define rt return
    #define dll(x) scanf("%I64d",&x)
    #define xll(x) printf("%I64d
    ",x)
    #define sz(a) int(a.size())
    #define all(a) a.begin(), a.end()
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
    inline void getInt(int* p);
    const int maxn=100010;
    const int inf=0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    std::vector<int> son[maxn];
    const ll mod=1e9+7ll;
    ll ans=0ll;
    ll a[maxn];
    ll b[maxn];
    ll num[maxn];
    int du[maxn];
    int main()
    {
        // freopen("D:\common_text\code_stream\in.txt","r",stdin);
        //freopen("D:\common_text\code_stream\out.txt","w",stdout);
        gbtb;
        int n,m;
        while(cin>>n>>m)
        {
            repd(i,1,n)
            {
                son[i].clear();
            }
            MS0(du);
            MS0(num);
            repd(i,1,n)
            {
                cin>>a[i]>>b[i];
            }
            int x,y;
            repd(i,1,m)
            {
                cin>>x>>y;
                son[x].push_back(y);
                du[y]++;
            }
            queue<int> q;
            repd(i,1,n)
            {
                if(!du[i])
                {
                    q.push(i);
                }
            }
    
            ans=0ll;
            while(q.size())
            {
                int temp=q.front();
                q.pop();
                for(auto x:son[temp])
                {
                    ans=(ans+(a[temp]*b[x])%mod+mod)%mod;
                    a[x]+=a[temp];
                    a[x]=(a[x]+mod)%mod;
                    du[x]--;
                    if(!du[x])
                    {
                        q.push(x);
                    }
                }
            }
            cout<<ans<<endl;
    
        }
    
    
    
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }

    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    ResGen.exe 生成resources文件方法 [转]
    C#【Winform】带参启动外部EXE
    SBO的5个开发原则机遇只给有准备的人[转]
    在SQL中插入临时表时使用自动增长的数据字段
    c# 强制退出
    C#实现SQL全库检索数据比较使用DataReader与DataAdapter+Datatable效率,差距惊人!
    推荐一个C#代码混淆器 .NET Reactor
    面向对象软件设计——设计模式学习
    AbstarctFactory模式——设计模式学习
    插入排序算法(直接,折半,希尔)
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/10679978.html
Copyright © 2011-2022 走看看