UVA 11468 - Substring (AC自动机 概率DP)

49 篇文章 0 订阅
39 篇文章 0 订阅

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

[Submit]   [Go Back]   [Status]  

Description

Download as PDF

H

Substring

Input: Standard Input

Output: Standard Output

 

Given a set of pattern strings, anda text, you have to find, if any of the pattern is a substring of the text. Ifany of the pattern string can be found in text, then print “yes”, otherwise“no” (without quotes).

But, unfortunately, that’s notwhat is asked here. J

The problem described above,requires a input file generator. The generator generates a text of lengthL, by choosing L characters randomly. Probability of choosing each character isgiven 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 casestarts with an integerK, the numberof pattern strings. Next K lines eachcontain a pattern string, followed by an integerN, number of valid characters. Next N lines each contain acharacter 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 thevalid characters, given above.

 

There will be a blank line aftereach test case.

 
Output

For each test case, output the number of test case, and theprobability 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

SampleInput                             Outputfor Sample Input

2

1

a

2

a 0.5

b 0.5

2

 

2

ab

ab

2

a 0.2

b 0.8

2

Case #1: 0.250000

Case #2: 0.840000


Problem Setter: Manzurur Rahman Khan

[Submit]   [Go Back]   [Status]  


题意:

给出一些字符和各自出现的概率,随机选择L次得到一长为L的字符串S,给k个模板串,计算S不包含任何一个模板串的概率。



AC自动机+dp


先用所给模板串构造出AC自动机

AC自动机其实是在Trie树上面加了Fail数组,在构造自动机的时候顺便标记出哪些节点是不能经过的(单词结尾,单词为当前节点后缀的也就是Last[u]如果是不能经过的,那么当前节点u也不能经过)。


然后DP[i][j]表示走到i节点还需要走j条边而不包含模板串(不经过被标记的节点)的概率

DP[i][j] = DP[k][j-1] k为可以走到的没有被标记的节点


输入的概率要初始化!



#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>

using namespace std;

//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif

#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)

const int INF = 0x3f3f3f3f;
const double eps = 10e-9;
const double PI = (4.0*atan(1.0));

const int MAX_NODE = 500 + 20;
const int SIGMA_SIZE = 62;

struct ACAutomata {
    int ch[MAX_NODE][SIGMA_SIZE];
    bool isWord[MAX_NODE];
    int sz;
    int f[MAX_NODE];
    void init() {
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
        memset(isWord, 0, sizeof(isWord));
    }
    int idx(char c) {
        if('0' <= c && c <= '9') return c - '0';
        if('A' <= c && c <= 'Z') return c - 'A' + 10;
        if('a' <= c && c <= 'z') return c - 'a' + 36;
    }
    void insert(char * s) {
        int n = strlen(s);
        int u = 0;
        for(int i=0; i<n; i++) {
            int c = idx(s[i]);
            if(!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                isWord[sz] = false;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        isWord[u] = true;
    }
    void build() {
        queue<int> Q;
        f[0] = 0;
        for(int i=0; i<SIGMA_SIZE; i++) {
            int u = ch[0][i];
            if(u) { Q.push(u); f[u] = 0; }
        }
        while(!Q.empty()) {
            int r = Q.front();
            Q.pop();
            for(int c=0; c<SIGMA_SIZE; c++) {
                int u = ch[r][c];
                if(!u) {
                    ch[r][c] = ch[f[r]][c];
                    continue;
                }
                Q.push(u);
                int v = f[r];
                while(v && !ch[v][c]) v = f[v];
                f[u] = ch[v][c];
                isWord[u] |= isWord[f[u]];
            }
        }
    }
};

char s[100];
ACAutomata ac;
int vis[MAX_NODE][120];
double dp[MAX_NODE][120];
double p[SIGMA_SIZE];

double getProb(int u, int L) {
    if(!L) return 1.0;
    if(vis[u][L]) return dp[u][L];
    vis[u][L] = 1;
    double & res = dp[u][L];
    res = 0.0;
    for(int c=0; c<SIGMA_SIZE; c++) {
        if(!ac.isWord[ac.ch[u][c]]) res += p[c] * getProb(ac.ch[u][c], L-1);
    }
    return res;
}

int main() {
    int T;

    scanf("%d", &T);
    for(int kase=1; kase<=T; kase++) {
        int k;
        ac.init();
        scanf("%d", &k);
        for(int i=0; i<k; i++) {
            scanf("%s", s);
            ac.insert(s);
        }
        ac.build();
        int m;
        scanf("%d", &m);
        // p一定要初始化!
        for(int i=0; i<SIGMA_SIZE; i++) p[i] = 0;
        for(int i=0; i<m; i++) {
            double tp;
            scanf("%s%lf", s, &tp);
            p[ac.idx(s[0])] = tp;
        }
        int L;
        scanf("%d", &L);
        memset(vis, 0, sizeof(vis));
        double ans = getProb(0, L);
        printf("Case #%d: %.6lf\n", kase, ans);
    }

    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值