zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    Android中WebView如何加载JavaScript脚本
    Android中WebView如何加载JavaScript脚本
    Android中WebView如何加载JavaScript脚本
    Android如何使用SQLlite数据库
    Android如何使用SQLlite数据库
    Android如何使用SQLlite数据库
    __declspec(dllimport)的作用
    __declspec,__cdecl,__stdcall都是什么意思?有什么作用?
    #pragma pack(push,1)与#pragma pack(1)的区别
    #pragma pack(n) 的作用
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9467123.html
Copyright © 2011-2022 走看看