1804: 有向无环图
Time Limit: 5 Sec Memory Limit: 128 Mb Submitted: 732 Solved: 305Description
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,v
i≤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
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define MOD 1000000007 #define MAX 100005 //数组开的太大了,我用的是codeblocks导致一直运行不了,后来发现数组开大了,定义为全局变量就好, //全局变量是存储在数据区的,而局部变量是用栈存储的,栈太小,会溢出 using namespace std; vector<int> list[MAX]; long long a[MAX],b[MAX]; int degree[MAX]; long long sum[MAX]; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { memset(degree,0,sizeof(degree)); memset(list,0,sizeof(list)); memset(sum,0,sizeof(sum)); for(int i=1; i<=n; i++) { scanf("%lld%lld",&a[i],&b[i]); sum[i]=b[i]; } for(int i=1; i<=m; i++) { int fa,son; scanf("%d%d",&fa,&son); degree[fa]++;//记录从fa出发的路径数 list[son].push_back(fa);//记录到son的点 } queue<int> original; queue<int> sorted; for(int i=1; i<=n; i++) { if(degree[i]==0) original.push(i);//没有出度的入队 } while(!original.empty())//队列不为空 { int son=original.front();//读取最底端元素 original.pop();//出队(先进先出)取出最底端元素 for(int i=0; i<list[son].size(); i++) { int fa=list[son][i]; degree[fa]--; if(degree[fa]==0) original.push(fa); } sorted.push(son); } long long ans=0; while(!sorted.empty())//队列不为空 { int son=sorted.front(); sorted.pop(); /*eg:4 4 1 1 1 1 1 1 1 1 1 2 1 3 2 3 1 4 出队的顺序是3 4 2 1 这样子的话首先计算的是以3为终点的路径,分别是1->3,2->3 1->3:ans=ans+a[1]*b[3]=1;b[1]=b[1]+b[3]=2; 2->3:ans=ans+a[2]*b[3]=2;b[2]=b[2]+b[3]=2; 接着就是 1->4:ans=ans+a[1]*b[4]=3;b[1]=b[1]+b[4]=3; 然后 1->2:ans=ans+a[1]*b[2]=5;b[1]=b[1]+b[2]=5; 从数据可以看出算1->2的时候其实是这样子算的,首先加上原来累加的,其次b[2]=b[2]+b[3],这样是因为1->2->3 也可以这样子认为1->3的时候只计算了一次b[3],到1->2的时候要多加一个b[3],这个地方一开始想错了,以至于钻了好久的牛角尖, 还是得自己慢慢领悟吧! */ for(int i=0; i<list[son].size(); i++) { int fa=list[son][i]; ans=(ans+(a[fa]*sum[son])%MOD)%MOD; sum[fa]=(sum[fa]+sum[son])%MOD; } } printf("%lld\n",ans%MOD); } return 0; }