link
给出一张图,\(N\) 个点 \(M\) 条边,每个点有一个初始权值 \(a_i\)
接下来有 \(K\) 次操作,每次相互独立
- 随机选中一条边 \(<u,v>\),将 \(a_u\) 和 \(a_v\) 修改成\((a_u+a_v)/2\)
求出最后每个点的期望大小
solve
分别考虑 \(a_i\) 对自己的影响和其他的影响
设 \(d_i\) 为 \(i\) 的度
- 自己最自己影响
对于一个点,本来对他自己的贡献是 \(a_i\) ,但是由于和他连接的有 \(d_i\) 条边,所以他们被选中的概率是 \(d_i\over m\),每一条边被选中,这个点 的贡献会从本来的 \(a_i\) 变成 \(a_i\over 2\),所以用 \(1\) 减去少掉的贡献,所以自己对自己的贡献就是 \(a_i\times (1-{d_i\over {m\times 2}})\)
所以概率矩阵 \(a[i][i]= 1-{d_i\over {m\times 2}}\)
- 和自己连边的点对自己的贡献
对于任意一条边 \(<u,v>\),显然选择到该边的概率为 \(1\over m\) ,一条边对自己的概率的影响是 \(1\over m\) ,所以概率矩阵 \(a[i][j]=1\over{2\times m}\)
剩下的就是矩阵快速幂,算出 \(k\) 时刻的期望,乘上 \(a_i\)就是期望了
code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=105;
const LL TT=1e9+7;
int N,du[maxn],M,K,a[maxn];
LL ans;
struct Matrix{
int V[maxn][maxn];
Matrix(){memset(V,0,sizeof V);}
friend Matrix operator *(Matrix A,Matrix B){
Matrix C;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
for(int k=1;k<=N;k++)
C.V[i][j]=(C.V[i][j]+1LL*A.V[i][k]*B.V[k][j])%TT;
return C;
}
}E,G;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int Pow(int a,int b){
int s=1,w=a;
while(b){
if(b&1)s=1LL*s*w%TT;w=1LL*w*w%TT;b>>=1;
}
return s;
}
int main(){
freopen("F - Graph Smoothing.in","r",stdin);
freopen("F - Graph Smoothing.out","w",stdout);
N=read();M=read();K=read();
for(int i=1;i<=N;i++) a[i]=read();
for(int i=1;i<=M;i++){
int x=read(),y=read();
E.V[x][y]=E.V[y][x]=1;
du[x]++;du[y]++;
}
int Inv_2m=Pow(2*M,TT-2);
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++)if(E.V[i][j]) E.V[i][j]=Inv_2m;
E.V[i][i]=(1ll*2*M-du[i])*Inv_2m%TT;
}
for(int i=1;i<=N;i++) G.V[i][i]=1;
while(K){
if(K&1)
G=G*E;
E=E*E;
K>>=1;
}
for(int i=1;i<=N;i++){
ans=0;
for(int j=1;j<=N;j++)
ans=(ans+(1ll*G.V[j][i]*a[j])%TT)%TT;
printf("%lld\n",ans);
}
return 0;
}