UVA 11468 Substring [AC自动机] [全概率公式]

Substring
Time Limit: 10000MS
64bit IO Format: %lld & %llu

Given a set of pattern strings, and a text, you have to find, 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’, otherwise ‘no’ (without quotes).
But, unfortunately, thats not what is asked here.
The problem described above, requires a input file 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自动机上 dp , 可以用记忆化搜索写
不过get_fail 时 , 后面的单词不知道前面是否出现过, 所以在更新end(root) 时要看看 fail 上有没有!!
dfs时注意初始值!! ans = 0.0 再按照全概率公式加上去,并且注意处理不存在的情况!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef double LL;
const int INF=0x3f3f3f3f;
const int maxlen = 25;
const int maxk = 25;
const int maxl = 105;
const int SIGMA_SIZE = 26+26+10;
char s[maxlen];
int k,n;
LL pro[SIGMA_SIZE]; // sub for idx
LL dp[maxlen*maxk][maxl];
inline int idx(char c)
{
    if(c>='a' && c<='z') return c - 'a';
    if(c>='A' && c<='Z') return c - 'A' + 26;
    return c - '0' + 52;
}
struct Node
{
    bool end;
    int ch[SIGMA_SIZE];
    int fail;
}node[maxlen*maxk];
int maxnode;
#define end(x) node[x].end
#define ch(x,i) node[x].ch[i]
#define fail(x) node[x].fail
void insert(char s[])
{
    int lens = strlen(s);
    int root = 0;
    for(int i=0;i<lens;i++)
    {
        int c = idx(s[i]);
        if(!ch(root,c)) ch(root,c) = ++maxnode;
        root = ch(root,c);
    }
    end(root) = true;
}
void get_fail()
{
    queue <int> que;
    for(int i=0;i<SIGMA_SIZE;i++)
        if(ch(0,i)) que.push(ch(0,i));
    while(!que.empty())
    {
        int u = que.front(); que.pop();
        for(int i=0;i<SIGMA_SIZE;i++)
        {
            int v = ch(u,i);
            if(!v) { ch(u,i) = ch(fail(u),i); continue; }
            que.push(v);
            int root = fail(u);
            while(root && !ch(root,i)) root = fail(root);
            fail(v) = ch(root,i); // don't for get to visit son i of root
            end(v) |= end(fail(v)); // the same word isn't known before current string!!! Need to update!!!
        }
    }
}
inline void clear_ac()
{
    maxnode = 0;
    memset(pro,0,sizeof(pro));
    memset(node,0,sizeof(node));
    memset(dp,0,sizeof(dp));
}
inline void init()
{
    clear_ac();
    scanf("%d",&k);
    while(k--)
    {
        scanf("%s",s);
        insert(s);
    }
    get_fail();
    scanf("%d",&n);
    getchar();
    for(int i=1;i<=n;i++)
    {
        char ch = getchar();
        scanf("%lf",&pro[idx(ch)]);
        getchar();
    }
}
LL dfs(int root,int last)
{
    if(dp[root][last]!=0.0) return dp[root][last];
    if(!last) return 1.0;
    LL ans = 0.0; // from 0.0 to add!!
    for(int i=0;i<SIGMA_SIZE;i++)
    {
        int v = ch(root,i);
        if(end(v)) continue;
        if(pro[i]!=0.0) ans += pro[i]*dfs(v,last-1); // update only if pro[i] exists and + here!!! Total Probability Formula
    }
    return dp[root][last] = ans;
}
int main()
{
    freopen("sub.in","r",stdin);
    freopen("sub.out","w",stdout);
    int t,cas=0;
    scanf("%d",&t);
    while(t--)
    {
        init();
        int L;
        scanf("%d",&L);
        LL ans = dfs(0,L);
        printf("Case #%d: %.6lf\n",++cas,ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值