题意:
Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
为了方便,点用 1,2,…,n 编号。 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0),Bobo 想知道
除以 (109+7) 的余数。
其中,ai,bj 是给定的数列。
dp题~~~比赛的时候没有想出来。想开一个dp[MAX][MAX],但是数据太大了开不了。
实际上我们应该这样将表达式转换成 count[i][j]表示i到j的路径。一条路就是 a[i]*b[j]
2条就是,a[i]*(b[j]+b[j]);我们先算出 i能到的其他点,例如 i可以直连到 3 5 4 6;
则用一个数组表示 sum【i】=b[3]+b[5]+b[4]+b[6],那么这一段再用a[i]*sum[i],就得到结果了;
那么我们sum[i]表示的是 以i为父亲或者祖先的所有节点的b的和。
Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
为了方便,点用 1,2,…,n 编号。 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0),Bobo 想知道
除以 (109+7) 的余数。
其中,ai,bj 是给定的数列。
dp题~~~比赛的时候没有想出来。想开一个dp[MAX][MAX],但是数据太大了开不了。
实际上我们应该这样将表达式转换成 count[i][j]表示i到j的路径。一条路就是 a[i]*b[j]
2条就是,a[i]*(b[j]+b[j]);我们先算出 i能到的其他点,例如 i可以直连到 3 5 4 6;
则用一个数组表示 sum【i】=b[3]+b[5]+b[4]+b[6],那么这一段再用a[i]*sum[i],就得到结果了;
那么我们sum[i]表示的是 以i为父亲或者祖先的所有节点的b的和。
这个有点像树形dp
代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<vector>
#include<string>
#include<queue>
using namespace std;
#define MAX (10*10*10*10*10+10)
#define LL long long
#define mod (10*10*10*10*10*10*10*10*10+7)
vector<int>G[MAX];
LL a[MAX];
LL b[MAX];
LL in[MAX];
LL int n,m;
LL dp[MAX];
int main()
{
while(scanf("%lld %lld",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%lld %lld",&a[i],&b[i]);
G[i].clear();
}
memset(in,0,sizeof(in));
for(int i=1;i<=m;i++)
{
int x,y;//反向建图
scanf("%d %d",&x,&y);
G[y].push_back(x);
in[x]++;
}
memset(dp,0,sizeof(dp));
queue<int>q;//反向建图,按照拓扑排序求dp[i]
for(int i=1;i<=n;i++)
{
if(in[i]==0) q.push(i);
}
int now, next;
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=0;i<G[now].size();i++)
{
int next=G[now][i];
dp[next]=dp[next]%mod+(dp[now]%mod+b[now]%mod)%mod;//一个小分支的b。
in[next]--;
if(in[next]==0)
{
q.push(next);
}
}
}
long long int res=0;
for(int i=1;i<=n;i++)
{
res=(res%mod+((a[i]%mod)*(dp[i]%mod))%mod);
}
printf("%lld\n",res);
}
}