中文题:
在一个N个点(标号1~n),M条边的有向图上,一开始我在点u,每一步我会在当前点的出边中等概率的选一条走过去,求走了恰好K步后走到每个点的概率.
第一行两个正整数N,M,表示点数和边数. 接下来M行,每行两个正整数X,Y.表示一条X向Y的一条有向边(保证没有重边和自环). 接下来一个正整数Q,表示询问个数. 接下来Q行,每行两个正整数u,K,表示开始的点和步数. N≤50,M≤1000,Q≤20,u≤n,K≤109. 每个点保证至少有一个出边.
Q行,每行N个数字,用空格隔开,第i个数字表示从u开始走K步到i的概率. 考虑到输出的答案可能会有精度问题,经过一定的分析后可以发现答案一定可以被表示成YX的形式,你只需输出X×Y109+5 mod (109+7)的值即可. 在每行后面多输出一个空格,否则可能会使你PE.
3 2 1 2 1 3 1 1 1
0 500000004 500000004
这是一个三个点,两条边的有向图,它们分别是(1−>2,1−>3).现在在1号点,走了一步后,有1/2的概率走到了2,有1/2的概率走到了3,本来应该输出 0 0.5 0.5 而根据上面所说的,应输出1∗2109+5 mod (109+7)=500000004.
解题思路:
graph
考虑dpdpdp,用ft,xf_{t,x}ft,x表示第ttt秒在xxx的概率,初始时f0,u=1f_{0,u}=1f0,u=1.
ft+1,y=∑x,x−>yft,xOutx,Outxf_{t+1,y}=\sum_{x,x->y}{\frac{f_{t,x}}{Out_x}},Out_xft+1,y=∑x,x−>yOutxft,x,Outx表示xxx的出度.
因为ttt很大,而且发现每次的转移都是相同的,所以直接矩乘就好了.
复杂度是O(QN3logt)O(QN^3\log t)O(QN3logt).
考虑成矩阵就是i到j的概率,初始化矩阵就是第一步的情况。进行k次相乘就是结果了。注意结果要求,初始化数据出度进行一次快速幂就可以了。
AC代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long LL; const LL Mod=1000000007; const LL expn=1000000005; const int MAXN = 55; struct Matrix { LL a[MAXN][MAXN]; int r,c; }; Matrix multiply(Matrix x,Matrix y) { Matrix z; z.r=x.r;z.c=y.c; for(int i=0;i<z.r;i++){ for(int j=0;j<z.c;j++) z.a[i][j]=0; } for(int i=0;i<x.r;i++){ for(int k=0;k<x.c;k++){ if(x.a[i][k]){ for(int j=0;j<y.c;j++){ z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%Mod)%Mod; } } } } return z; } Matrix Mpower(Matrix x,int n) { Matrix res; res.r=x.r;res.c=x.c; for(int i=0;i<res.r;i++){ for(int j=0;j<res.c;j++){ if(i==j)res.a[i][j]=1; else res.a[i][j]=0; } } while(n){ if(n&1) res=multiply(res,x); x=multiply(x,x); n>>=1; } return res; } void Mpr(Matrix x) { for(int i=0;i<x.r;i++){ for(int j=0;j<x.c;j++){ printf("%d ",x.a[i][j]); } printf("\n"); } } LL power(LL x,LL n) { LL res=1; while(n){ if(n&1) res=res*x%Mod; x=x*x%Mod; n>>=1; } return res; } bool vis[MAXN][MAXN]; LL degree[MAXN]; int main() { int N,M; while(scanf("%d%d",&N,&M)!=EOF){ int X,Y; memset(degree,0,sizeof(degree)); memset(vis,false,sizeof(vis)); for(int i=0;i<M;i++){ scanf("%d%d",&X,&Y); vis[X-1][Y-1]=true; degree[X-1]++; } Matrix temp; for(int i=0;i<N;i++){ LL t=power(degree[i],expn); for(int j=0;j<N;j++){ if(vis[i][j]){ temp.a[i][j]=t; } } } temp.r=temp.c=N; int Q; scanf("%d",&Q); while(Q--){ int u,K; scanf("%d%d",&u,&K); Matrix ans; ans=Mpower(temp,K); for(int i=0;i<N;i++){ printf("%lld ",ans.a[u-1][i]); } printf("\n"); } } return 0; }