【CF446D】DZY Loves Games

题解:

不错的题目

首先要求的黑点个数非常多

比较容易想到矩阵乘法

于是我们可以求出从某个黑点出发到任意一个黑点之间的概率

发现不同出发点带来的变化只有常数项

于是我们可以预处理出从每个方程转移的系数

处理的方法就是 当行a减去k倍的行b时

我们同时更新行b被多少行更新了

求完之后我们只需要求它的k-2次幂

当然我们还需要求出起点1到每个黑点的概率(一起求)

矩阵乘法的比较优的写法是这样的

 

  rep(i,1,n)
    rep(j,1,n)
      if (x.a[j][i])
      rep(k,1,n)
        z.a[j][k]+=x.a[j][i]*y.a[i][k];

 

要再快可以使用分块乘法

高斯消元的时候由于f[i][i]=1,所以可以不去找最大值

因为那样的话我们处理哪些由哪些转移还要记录pos,比较麻烦

cf还卡栈。。快速幂要写成非递归形式的

 

代码:

 

#include <bits/stdc++.h>
#define rint register int
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
using namespace std;
const int N=6e5;
const int N2=600;
int head[N2],v[N2],du[N2],l,n,m,k,M[N2][N2];
double o2[N2];
double f[N2][N2],jl[N2][N2];
double ee=1.00000000000000000;
struct re{
  int a,b;
}a[N*2]; 
void arr(int x,int y)
{
  a[++l].a=head[x];
  a[l].b=y;
  head[x]=l;
}
struct re1{
  double a[600][600];
  re1()
  {
    rep(i,0,n)
      rep(j,0,n) a[i][j]=0; 
  }
}o;
re1 z;
re1 js(re1 x,re1 y)
{
  memset(z.a,0,sizeof(z.a)); 
  rep(i,1,n)
    rep(j,1,n)
      if (x.a[i][j])
      rep(k,1,n)
        z.a[i][k]+=x.a[i][j]*y.a[j][k];
  return(z);
}
re1 y;
re1 o3;
re1 fsp(rint x)
{
  memset(y.a,0,sizeof(y.a));
  o3=o;
  rep(i,1,n) y.a[i][i]=1;
  while (x)
  {
    if (x&1) y=js(y,o3);
    x>>=1;
    o3=js(o3,o3);
  }
  return(y);
}
int ve[N2],cnt=0;
void Gauss()
{
  rep(i,1,n) jl[i][i]=1;
  rep(i,1,n)
  {
    rep(j,1,n)
      if (i!=j)
      {
        double t=-f[j][i]/f[i][i];
        rep(k,1,n) f[j][k]+=t*f[i][k];
        rep(k,1,n) jl[j][k]+=t*jl[i][k];
      }
  }
  rep(i,1,n)
    if (v[i])
    {
      cnt=0;
      double tmp=ee/du[i];
      rep(j,1,n)
        if (M[i][j]) ve[++cnt]=j;
      rep(k,1,n)
        if (v[k])
        {
          double ans=0;
          rep(j,1,cnt) ans+=M[i][ve[j]]*jl[k][ve[j]]*tmp;
          o.a[i][k]=ans;
        }
    }
  rep(j,1,n)
    if (v[j])
      o2[j]=jl[j][1];
}
int main()
{
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  ios::sync_with_stdio(false);
  cin>>n>>m>>k;
  rep(i,1,n)
  { 
    cin>>v[i];
  }
  rep(i,1,m)
  {
    int x,y;
    cin>>x>>y;
    arr(x,y); arr(y,x);
    M[x][y]++; M[y][x]++;
    du[x]++; du[y]++;
  }
  rep(i,1,n)
  {
    f[i][i]=-1; 
    for (int u=head[i];u;u=a[u].a)
    {
      int vv=a[u].b;
      if (!v[vv]) f[i][vv]+=ee/du[vv];
    }
  }
  Gauss();
  double ans=0;
  if (k!=2)
  { 
    re1 ans2=fsp(k-2);
    rep(i,1,n)
      if (v[i]) ans+=o2[i]*ans2.a[i][n];
  } else
  if (k==2) ans=o2[n];
  else ans=0;
  printf("%.9f",ans);
  return 0;
}

 

posted @ 2018-08-13 11:34  尹吴潇  阅读(746)  评论(0编辑  收藏  举报