• 【noi2019集训题1】 脑部进食 期望dp+高斯消元


    题目大意:有n个点,m条有向边,每条边上有一个小写字母。

    有一个人从1号点开始在这个图上随机游走,游走过程中他会按顺序记录下走过的边上的字符。

    如果在某个时刻,他记录下的字符串中,存在一个子序列和S2相同,或者存在一个子串和S1相同,那么他就会当场去世。

    他想知道他会不会当场去世,如果会,他想问你当场去世的时间的期望。

    数据范围:n≤20,|S1|≤10,|S2|≤50

    我们考虑列一个dp方程出来

    设f[i][j][k]表示这人从1号点出发,当前走到i号点,且子串覆盖了S1的前j位,覆盖了S2的前k位的期望步数

    然后你会发现你做不出来,因为最终根本无法统计答案(然后你就进死胡同了)

    我们尝试把整个方程反过来

    设$f[i][j][k]$表示你从$i$号点出发,之前走的路已经覆盖了$S1$的前$j$位,$S2$串的前$k$位的情况下,期望走多少部后会去世。

    最终需要求的答案显然是$f[1][0][0]$

    我们不难列出$f[i][j][k]=1+frac{1}{d[i]} sumlimits_{(i,u)∈E}f[u][j'][k']$

    其中$d[i]$表示$i$号点的出度,$E$表示边集,$j'$和$k'$的具体值视该转移边的字母而订,非常好求。

    这个方程我们显然可以通过高斯消元求解,时间复杂度$O(n^3|S1|^3|S2|^3)$,愉快$TLE$

    无解的情况出现即为某一条方程出现了被零除。

    我们发现,从$f[i][j'][k']$向$f[i][j][k]$转移的过程中,有$k'≥k$

    那么我们显然可以固定$k$,对每一个$k$做一次高斯消元,然后向下一层传值,再高斯消元即可。

    时间复杂度于是就降低到$O(n^3|S1|^3|S2|)$了

    看起来有$4$个亿

    实际上因不明原因,每一层需要转移的节点数根本就去不到理论上届

    所以只跑了不到$20ms$(大雾)

     1 #include<bits/stdc++.h>
     2 #define M 205
     3 #define eps 1e-6
     4 using namespace std;
     5 
     6 double f[M][M]={0},ans[M]={0};
     7 
     8 void gauss(int n){
     9     for(int i=1;i<=n;i++){
    10         int id=i;
    11         for(int j=i;j<=n;j++) if(f[id][i]<f[j][i]) id=j;
    12         swap(f[i],f[id]);
    13         if(fabs(f[i][i])<eps) {printf("-1
    "); exit(0);}
    14         for(int j=i+1;j<=n;j++){
    15             double cha=f[j][i]/f[i][i];
    16             for(int k=i;k<=n+1;k++) f[j][k]-=f[i][k]*cha;
    17         }
    18     }
    19     for(int i=n;i;i--){
    20         for(int j=i+1;j<=n;j++) f[i][n+1]-=ans[j]*f[i][j];
    21         ans[i]=f[i][n+1]/f[i][i];
    22     }
    23 }
    24 
    25 struct edge{int u,next;char v;}e[600]={0}; int head[M]={0},use=0;
    26 void add(int x,int y,char z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
    27 int n,m;
    28 
    29 char w[M]={0},p[M]={0}; int lenw,lenp;
    30 int nxt[M]={0};
    31 
    32 void upd(char C,int id,int &nowj,int &nowk){
    33     for(;nowj&&w[nowj+1]!=C;nowj=nxt[nowj]);
    34     if(w[nowj+1]==C) nowj++;
    35     if(p[nowk+1]==C) nowk++;
    36 }
    37 
    38 int vis[22][11][55]={0};
    39 void dfs(int i,int j,int k){
    40     if(vis[i][j][k]) return;
    41     vis[i][j][k]=1;
    42     if(j==lenw||k==lenp) return;
    43     for(int l=head[i];l;l=e[l].next){
    44         char C=e[l].v; int id=e[l].u;
    45         int nowj=j,nowk=k;
    46         upd(C,id,nowj,nowk);
    47         dfs(id,nowj,nowk);
    48     }
    49 }
    50 
    51 int id[22][11]={0},iid[22][11]={0},cnt=0; double d[M]={0};
    52 
    53 int main(){
    54     scanf("%d%d",&n,&m);
    55     for(int i=1;i<=m;i++){
    56         int x,y; char z[10]; scanf("%d%d%s",&x,&y,z);
    57         add(x,y,z[0]); d[x]++;
    58     }
    59     scanf("%s",w+1); lenw=strlen(w+1);
    60     scanf("%s",p+1); lenp=strlen(p+1);
    61     for(int i=2,j=0;i<=n;i++){
    62         for(;j&&w[j+1]!=w[i];j=nxt[j]);
    63         if(w[j+1]==w[i]) j++;
    64         nxt[i]=j;
    65     }
    66     dfs(1,0,0);
    67     for(int k=lenp-1;~k;k--){
    68         int cnt=0;
    69         for(int i=1;i<=n;i++)
    70         for(int j=0;j<lenw;j++){
    71             id[i][j]=0;
    72             if(vis[i][j][k]) 
    73             id[i][j]=++cnt;
    74         }
    75         memset(f,0,sizeof(f));
    76         for(int i=1;i<=n;i++)
    77         for(int j=0;j<lenw;j++) if(id[i][j]){
    78             int ID=id[i][j];
    79             f[ID][ID]=d[i]; 
    80             f[ID][cnt+1]=d[i];
    81             for(int l=head[i];l;l=e[l].next){
    82                 char C=e[l].v; int u=e[l].u;
    83                 int nowj=j,nowk=k;
    84                 upd(C,u,nowj,nowk);
    85                 if(nowj==lenw) continue;
    86                 if(nowk==k){
    87                     f[ID][id[u][nowj]]--;
    88                 }else{
    89                     f[ID][cnt+1]+=ans[iid[u][nowj]];
    90                 }
    91             }
    92         }
    93         memcpy(iid,id,sizeof(id));
    94         memset(ans,0,sizeof(ans));
    95         gauss(cnt);
    96     }
    97     printf("%.10lf
    ",ans[1]);
    98 }

     

  • 相关阅读:
    CKA&CKAD考试
    进程线程和协程
    HTTP协议
    Centos操作系统启动流程
    高并发下的Linux内核参数优化
    DDoS防护系统建设的一些思路
    DDoS防护实现概述
    Nginx故障排查思路
    git常用指令集
    DNS实现粗粒度容灾
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/11017266.html
Copyright © 2020-2023  润新知