UVa 11468 Substring

来源:互联网 发布:安卓转java工具 编辑:程序博客网 时间:2024/04/29 11:26

        题意:给出一些字符和对应的选择概率,随机选择L次后得到一个长度为L的随机字符串S。给k个模板串,计算S不包含任何一个串的概率。

        思路:AC自动机+概率dp。之前我做这题一直WA,然后稍微改改代码交了下杭电上类似的题目居然1A了。。后来我才发现原因,是搜到字典树中间非叶子节点了以后,也应该试着往回跳,看看能不能跳到某个模板的末尾。但是杭电那题只有一个模板,所以才A掉的。不过杭电的题目背景比较有意思,好像是一个我小时候听过的故事,如果一个猴子随机敲键盘,可以敲出世界上任何一篇文章。。。

        回到正题。这题先建立一个AC自动机,然后从字典树树根开始,走L步,如果走到模板串的末尾,就不能再走下去了,边走边算概率。我是用递推dp来做的,dp(i,j)表示走到字典树的第i个节点,已经走了j步的概率。毕竟dp(i,j)有多条路线可以到达,全部加在一起算比较省时间,如果一条路走L步走到底会超时的。要注意的是,走到某个节点时,它本身不是模板串末尾并不代表可以继续走下去,应该往回跳看看是否会遇到模板串的末尾。最后结果是sum(dp(i,L))(i取所有的树节点)。


#include <iostream>             #include <stdio.h>             #include <cmath>             #include <algorithm>             #include <iomanip>             #include <cstdlib>             #include <string>             #include <memory.h>             #include <vector>             #include <queue>             #include <stack>             #include <map>           #include <set>           #include <ctype.h>           #define INF 1<<30         #define ll long long         #define max3(a,b,c) max(a,max(b,c))         using namespace std;#define maxnode 1010int T; //50int k; //20;int n; //int L;bool valid[65];double p[65];double dp[maxnode][110];int char2int(char c){if(c>='a'&&c<='z')return c-'a';if(c>='A'&&c<='Z')return c-'A'+26;if(c>='0'&&c<='9')return c-'0'+52;return -1; }// acint val[maxnode];int vis[maxnode][110];int ch[maxnode][65];int next[maxnode];int sz;double ans;void init(){sz=1;memset(ch[0],0,sizeof(ch[0]));memset(next,0,sizeof(next));memset(val,0,sizeof(val));}void insert(char* str){int u=0;int len=strlen(str);for(int i=0;i<len;i++){int v=char2int(str[i]);if( !ch[u][v] ){ch[u][v]=sz;memset(ch[sz],0,sizeof(ch[sz]));val[sz]=0;sz++;}u=ch[u][v];}val[u]++;}void build_ac(){memset(next,0,sizeof(next));queue<int> que; que.push(0);while(!que.empty()){int u=que.front(); que.pop();for(int i=0;i<62;i++){int v=ch[u][i];if(!v)continue;if(!u){next[v]=0;que.push(v);}else{int k=next[u];while(k&&!ch[k][i]){k=next[k];}if(ch[k][i])k=ch[k][i];next[v]=k;//cout<<"next "<<v<<" = "<<k<<endl;que.push(v);}}}}//ac endint main(){scanf("%d",&T);int cas=0;while(T--){cas++;memset(valid,0,sizeof(valid));memset(vis,0,sizeof(vis));ans=0;init();//scanf("%d",&k);for(int i=1;i<=k;i++){char pattern[30];scanf("%s",pattern);insert(pattern);}build_ac();//scanf("%d",&n);for(int i=1;i<=n;i++){char a;double b;cin>>a>>b;valid[char2int(a)]=1;p[char2int(a)]=b;}//scanf("%d",&L);for(int i=0;i<maxnode;i++){for(int j=0;j<=L;j++)dp[i][j]=0.0;}dp[0][0]=1.0; vis[0][0]=1;for(int i=1;i<=L;i++){for(int j=0;j<maxnode;j++){if(!vis[j][i-1])continue;for(int k=0;k<62;k++){if(!valid[k])continue;int v=j;while(v&&!ch[v][k]){v=next[v];}if(ch[v][k])v=ch[v][k];int tmp=v;bool skip=0;while(tmp){if(val[tmp]){skip=1;break;}tmp=next[tmp];}if(skip)continue;dp[v][i]+=dp[j][i-1]*p[k];vis[v][i]=1;}}}for(int i=0;i<maxnode;i++){ans+=dp[i][L];}printf("Case #%d: %.6lf\n",cas,ans);}return 0;}


0 0
原创粉丝点击