zoukankan      html  css  js  c++  java
  • 【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 }

     

  • 相关阅读:
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)
    install ubuntu on Android mobile phone
    Mac OS, Mac OSX 与Darwin
    About darwin OS
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十)
    Linux下编译安装qemu和libvirt
    libvirt(virsh命令总结)
    深入浅出 kvm qemu libvirt
    自然语言交流系统 phxnet团队 创新实训 项目博客 (九)
    自然语言交流系统 phxnet团队 创新实训 项目博客 (八)
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/11017266.html
Copyright © 2011-2022 走看看