UVa11468 Substring[AC自动机]

7 篇文章 0 订阅
4 篇文章 0 订阅

Given a set of pattern strings, and a text, you have to nd, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print yes', otherwiseno’ (without quotes).
But, unfortunately, thats not what is asked here.
The problem described above, requires a input le generator. The generator generates a text of length L, by choosing L characters randomly. Probability of choosing each character is given as priori,and independent of choosing others.
Now, given a set of patterns, calculate the probability of a valid program generating \no”.
Input
First line contains an integer T , the number of test cases. Each case starts with an integer K, the number of pattern strings. Next K lines each contain a pattern string, followed by an integer N,number of valid characters. Next N lines each contain a character and the probability of selecting that
character, pi. Next an integer L, the length of the string generated. The generated text can consist of only the valid characters, given above.
There will be a blank line after each test case.
Output
For each test case, output the number of test case, and the probability of getting a \no”.
Constraints:
T 50
K 20
Length of each pattern string is between 1 and 20
Each pattern string consists of only alphanumeric characters (a to z, A to Z, 0 to 9)
Valid characters are all alphanumeric characters

∑pi = 1
L 100
Sample Input
2
1
a
2
a 0.5
b 0.5
2
2
ab
ab
2
a 0.2
b 0.8
2
Sample Output
Case #1: 0.250000
Case #2: 0.840000

题意:给出不同字符的被选中的可能和一些不能出现的单词,求用给定的字符全部都不出现的概率。
分析:其实就是在AC自动机上走,不走到单词节点的可能性。那么如果走到尽头(dep==0),则这时可能性为1,然后在当前情况枚举所有单词看能不能走,如果此单词未出现,那么概率为0,如果出现了但是不是单词节点,就返回单词本身出现的概率乘以下一步递归(ch[u][i],dep-1),即走去这个单词的节点以及深度要减一。
然后解释一下这个match数组,match和sig有一点像,是记录这个位置是否单词节点,但由于这里采用的一视同仁(即补边)方式,所以match在每次找last的地方直接或上它的nxt节点,确保所有单词节点都会被match记录到(也就是说,只要出现了一个单词就不行,所以这里的match必须或,即考虑所有情况。
程序:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define clr(x) memset(x,0,sizeof(x))
using namespace std;
const int maxn=20*20+5;
int n,m,nxt[maxn],ch[maxn][80],len,inde,vi[maxn][105],match[maxn];
char s[25],tmp;
double f[maxn][105],val[80];
int calc(char c)
{
    if(c<='z'&&c>='a')return c-'a';
    else if(c<='9'&&c>='0')return 26+c-'0';
    else return 36+c-'A';
}
void insert()
{
    int u=0;len=strlen(s);
    for(int i=0;i<len;i++){
        if(!ch[u][calc(s[i])])
            ch[u][calc(s[i])]=++inde;
        u=ch[u][calc(s[i])];
    }
    match[u]=1;
}
void getfail()
{
    queue<int>q;
    for(int i=0;i<=61;i++)if(ch[0][i])
        q.push(ch[0][i]);
    while(!q.empty()){
        int cur=q.front();q.pop();
        for(int i=0;i<=61;i++)if(ch[cur][i]){
            int u=ch[cur][i];
            q.push(u);
            int j=nxt[cur];
            while(j&&!ch[j][i])j=nxt[j];
            nxt[u]=ch[j][i];
            match[u]|=match[nxt[u]];
        }else ch[cur][i]=ch[nxt[cur]][i];
    }
}
double lookfor(int u,int dep)
{
    if(!dep)return 1.0;
    if(vi[u][dep])return f[u][dep];
    vi[u][dep]=1;
    for(int i=0;i<=61;i++)if(!match[ch[u][i]])
        f[u][dep]+=val[i]*lookfor(ch[u][i],dep-1);
    return f[u][dep];
}
void init()
{
        inde=0;clr(ch);clr(nxt);
        clr(f);clr(val);clr(vi);clr(match);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",s);
            insert();
        }
        getfail();
        scanf("%d",&m);getchar();
        for(int i=1;i<=m;i++){
            scanf("%c",&tmp);
            scanf("%lf",&val[calc(tmp)]);
            getchar();
        }
            scanf("%d",&len);
}
int main()
{
    freopen("UVa11468.in","r",stdin);
    freopen("UVa11468.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        init();
        printf("Case #%d: %.6lf\n",i,lookfor(0,len));
    }
    return 0;
}

还有就是要注意,这里的符号一共有62种情况…我RE了好多次…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值