UpdateAfterEvent

Description

  小松鼠打了10个小时的游戏,一脸满足。却发现周围再次围满了游客,逃!

  她发现整个西湖内的松鼠都以相同的速度在树之间跳跃。每跳跃一次花费一个单位的时间。我们可以把西湖抽象为一张n个点的无向图,初始时每个点上都有若干只松鼠,它们每单位时间都可以沿着一条无向边进行跳跃。

  对于一只当前在点i的松鼠,它在接下来的一个单位时间内等概率向相邻的点跳跃。更具体地讲,我们称与点i通过一条无向边直接相连的点为与i相邻的点,假设这样的点有p个,那么对于每一个与i相邻的点,在下一时刻都有1/p的概率跳到它。

  超萌小松鼠已知初始时刻(0时刻)每棵树上的松鼠分布情况,她想知道在T时刻,在同一棵树上的松鼠对数的期望。关于“松鼠对数”的解释:假设有4只松鼠在同一棵树上,那么我们称有6对在同一棵树上的松鼠。为了避免精度误差,我们将答案模10^9 + 7输出。

Input

  第一行三个数n,T。意义如题面中所述。接下来一行n个数,第i个数ai表示第i个点初始时刻有ai只松鼠。接下来n行,每行n个数,第i行第j个数如果为1表示点i与点j间有无向边相连,为0则表示没有。

Output

  输出一行一个数,表示T时刻在同一棵树上的松鼠对数的期望在模10^9 +7意义下的答案。

Solution

这道题考察了许多知识点,考察综合能力。

首先,题目总体是考察概率期望,但切忌陷入思路死角,去求每棵树上的最终期望松鼠对数。实际上,我们对于每只松鼠,去求它到某点的概率p,那么每两只松鼠在某点的期望便是p1*p2*1(还有很多可转化为概率来做的期望题)由于要除法取模,要预先递推求出逆元,复习一下公式:inv[1]=1;inv[i]=(mod-mod/i)*inv[mod%i]%mod. 

那么对于松鼠到某点的概率求取,我们先O(N^2)求出最开始互相连点之间的概率,然后每一时刻,枚举中间点,进行概率传递,由于t比较大,可以用矩阵快速幂思想来将其优化到log2n级别。

最后,由于我们计算期望是O(n^3)的,无法过n<=1000的点,发现如下式子:

设p(i,j)为i到j点的概率。假设计算终点在1,则ans=p(1,1)*p(2,1)+p(1,1)*p(3,1)*.....+p(1,1)*p(n,1)+p(2,1)*p(3,1)+p(2,1)*p(4,1)+.......发现可以转化为p(1,1)*(p(2,1)+p(3,1)+p(4,1)+....+p(n,1))+p(2,1)*(p(3,1)+p(4,1)+.....+p(n,1)).由此发现是可以前缀和优化的,由此只用枚举一点和终点,从而变成O(N^2).当然可以每个统计一次,然后最后除以2.貌似更方便哈.....

上代码:

 1 #include<bits/stdc++.h>
 2 #define maxn 1005
 3 using namespace std;
 4 typedef long long ll;
 5 const ll mod=1e9+7;
 6 struct matrix{
 7     ll a[maxn][maxn];
 8 }nd,ans;
 9 int n,t,e[maxn][maxn];
10 matrix operator *(matrix &x,matrix &y){
11     matrix c;
12     memset(c.a,0,sizeof(c.a));
13     for(int i=1;i<=n;i++)
14     for(int j=1;j<=n;j++)
15     for(int k=1;k<=n;k++){
16         c.a[i][j]=(c.a[i][j]+(x.a[i][k]*y.a[k][j])%mod)%mod;
17     }
18     return c;
19 }
20 void pow(int t){
21     for(int i=1;i<=n;i++) ans.a[i][i]=1;
22     while(t){
23         if(t&1) ans=ans*nd;//最后为1 
24         nd=nd*nd;
25         t/=2;
26     }
27 }
28 ll p[maxn][maxn],inv[maxn],v[maxn];
29 void init(){
30     scanf("%d%d",&n,&t);
31     for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
32     inv[1]=1;
33     for(int i=2;i<=1000;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
34     for(int i=1;i<=n;i++)
35     for(int j=1;j<=n;j++) scanf("%d",&e[i][j]);
36     memset(nd.a,0,sizeof(nd.a));
37     for(int i=1;i<=n;i++){
38         int res=0;
39         for(int j=1;j<=n;j++)  res+=e[i][j];
40         for(int j=1;j<=n;j++)  nd.a[i][j]=inv[res]*e[i][j];
41     } 
42     if(t>1){
43         pow(t);
44         for(int i=1;i<=n;i++)
45         for(int j=1;j<=n;j++) p[i][j]=ans.a[i][j];
46     }
47     else{
48         for(int i=1;i<=n;i++)
49         for(int j=1;j<=n;j++) p[i][j]=nd.a[i][j];
50     }
51     
52     ll calc=0; 
53     for(int i=1;i<=n;i++){
54         ll t1=0,t2=0;
55         for(int j=1;j<=n;j++){
56             ll tt=(p[j][i]*v[j])%mod;
57             t1=(t1+tt)%mod;
58             t2=(t2+tt*p[j][i])%mod;
59         }
60         calc=(calc+(t1*t1%mod-t2+mod)%mod*inv[2]%mod)%mod;
61     }
62     printf("%lld",calc);
63 }
64 int main(){
65     init();
66     
67     return 0;
68 }
原文地址:https://www.cnblogs.com/degage/p/9718709.html