kuangbinOJ 1216 Gambler (ac自动机+概率dp)

来源:互联网 发布:淘宝自拍风格 滤镜 编辑:程序博客网 时间:2024/05/24 05:45

题意:

两个人分别拥有两个串P,Q,现在两个人玩掷硬币游戏,从一个空串开始,如果正面向上那么就在串后面+'1'否者+'0'。一旦这串中包含了P或者Q串就停止比赛,如果包含P则A赢,包含Q则B赢,否则平局。现在问A和B赢的概率分别是多少。

题解:

这题要分别对A赢和B赢进行dp,应为有平局的情况。那对于A赢dp,将P插入自动机标记为1,插入自动机标记-1,这样在建机时就将包含P和不包含Q的分开了!然后dp[i][j]表示掷硬币第i轮,走到自动机j节点对应的概率。对于B同理。

OJ问题ac不了。


#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<set>using namespace std;#define B(x) (1<<(x))void cmax(int& a,int b){ if(b>a)a=b; }void cmin(int& a,int b){ if(b<a)a=b; }typedef long long ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const int MOD=2012;const int maxn=55;const int SIZE=maxn*maxn*2;char P[maxn],Q[maxn];double dp[maxn][SIZE];struct AC_Autometon{    int next[SIZE][2],fail[SIZE],flag[SIZE];    int cnt,root;    int newNode(){        for(int i=0;i<2;i++)            next[cnt][i]=-1;        flag[cnt]=0;        return cnt++;    }    void Init(){        cnt=0;        root=newNode();    }    void Insert(char buff[],int id){        int now=root;        for(int i=0;buff[i];i++){            int k=buff[i]-'0';            if(next[now][k]==-1)                next[now][k]=newNode();            now=next[now][k];        }        flag[now]=id;    }    void build(){        queue<int>q;        int now=root;        for(int i=0;i<2;i++){            if(next[now][i]==-1)                next[now][i]=root;            else{                fail[next[now][i]]=root;                q.push(next[now][i]);            }        }        while(!q.empty()){            now=q.front();q.pop();            if(flag[fail[now]]!=-1) flag[now]+=flag[fail[now]];            if(flag[fail[now]]==-1) flag[now]=-1;            for(int i=0;i<2;i++){                if(next[now][i]==-1)                    next[now][i]=next[fail[now]][i];                else{                    fail[next[now][i]]=next[fail[now]][i];                    q.push(next[now][i]);                }            }        }    }    double DP(int n){        memset(dp,0,sizeof dp);        double ans=0;        dp[0][0]=1;        for(int i=0;i<n;i++){            for(int j=0;j<cnt;j++){                if(flag[j]!=0)continue;                for(int t=0;t<2;t++){                    int k=next[j][t];                    if(flag[k]!=-1)                        dp[i+1][k]+=dp[i][j]*0.5;                }            }        }        for(int i=1;i<=n;i++){            for(int j=0;j<cnt;j++){                if(flag[j]>0)                    ans+=dp[i][j];            }        }        return ans;    }    void Debug(){        for(int i=0;i<cnt;i++){            printf("%d ch[ ",i);            for(int j=0;j<2;j++)                printf("%d ",next[i][j]);            puts("]");        }    }}ac;int main(){    //freopen("G:\\read.txt","r",stdin);    int K,T;    double ans1,ans2;    scanf("%d",&T);    while(T--){        scanf("%s%s",P,Q);        scanf("%d",&K);        ac.Init();        ac.Insert(P,1);        ac.Insert(Q,-1);        ac.build();        ans1=ac.DP(K);        ac.Init();        ac.Insert(Q,1);        ac.Insert(P,-1);        ac.build();        ans2=ac.DP(K);        printf("%.9lf %.9lf\n",ans1,ans2);    }    return 0;}/**2010001250115*/


0 0