• UVA11468 Substring


    思路

    AC自动机+概率dp

    设f[i][j]表示当前在第i位在AC自动机的第j个节点,满足条件的概率

    AC自动机上的一个节点能被转移到当且仅当这个节点不是中止节点且无法通过fail指针跳到任何一个中止节点

    答案就是(sum_{xin node} dp[L][x])

    注意本题字符集为0~9,A~Z,a~z

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    int Trie[410][64],fail[410],Nodecnt,root,ban[410],a[410],K,N,L;
    double f[110][410],p[410];
    char s[410];
    int tonum(char c){
        if(c>='a'&&c<='z')
            return c-'a';//0~25
        else if(c>='A'&&c<='Z')
            return c-'A'+26;//26~51
        else if(c>='0'&&c<='9')
            return c-'0'+52;
    }
    void insert(char *s,int len){
        int o=root;
        for(int i=0;i<len;i++){
            if(!Trie[o][tonum(s[i])])
                Trie[o][tonum(s[i])]=++Nodecnt;
            o=Trie[o][tonum(s[i])];
        }
        ban[o]=true;
    }
    queue<int> q;
    void get_AC(void){
        for(int i=0;i<64;i++){
            if(Trie[root][i]){
                fail[Trie[root][i]]=root;
                if(ban[fail[Trie[root][i]]])
                    ban[Trie[root][i]]=true;
                q.push(Trie[root][i]);            
            }
        }
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=0;i<64;i++){
                if(Trie[x][i]){
                    fail[Trie[x][i]]=Trie[fail[x]][i]; 
                    if(ban[fail[Trie[x][i]]])
                        ban[Trie[x][i]]=true;
                    q.push(Trie[x][i]);
                }
                else
                    Trie[x][i]=Trie[fail[x]][i];
            }
        }
    }
    double dp(void){
        int o=root;
        f[0][root]=1.0;
        for(int i=0;i<L;i++){
            for(int j=0;j<=Nodecnt;j++)
                if(!ban[j])
                    for(int k=1;k<=N;k++)
                        if(!ban[Trie[j][tonum(a[k])]])
                            f[i+1][Trie[j][tonum(a[k])]]+=f[i][j]*p[k];
        }
        double ans=0;
        for(int i=0;i<=Nodecnt;i++)
            ans+=f[L][i];
        return ans;
    }
    void init(void){
        Nodecnt=0;
        root=0;
        memset(Trie,0,sizeof(Trie));
        memset(fail,0,sizeof(fail));
        memset(f,0,sizeof(f));
        memset(ban,0,sizeof(ban));
    }
    int main(){
        // freopen("test.in","r",stdin);
        // freopen("test.out","w",stdout);
        int T,cnt=0;
        scanf("%d",&T);
        while(T--){
            cnt++;
            init();
            scanf("%d",&K);
            for(int i=1;i<=K;i++){
                scanf("%s",s);
                insert(s,strlen(s));
            }
            scanf("%d",&N);
            for(int i=1;i<=N;i++){
                char c=getchar();
                while((c<'a'||c>'z')&&(c<'A'||c>'Z')&&(c<'0'||c>'9'))
                    c=getchar();
                // printf("c=%c
    ",c);
                a[i]=c;
                scanf("%lf",&p[i]);
            }
            scanf("%d",&L);
            get_AC();
            printf("Case #%d: %.6lf
    ",cnt,dp());
        }
        return 0;
    }
    
  • 相关阅读:
    sqlserver 数据查询效率优化
    上海亲戚朋友游套餐
    C# List集合去重操作注意点
    一个高级开发的基本工作职责和能力要求
    对于程序员的经验能力和薪资待遇基本概括
    一个项目团队的最低配置
    【算法学习笔记】51. 贪心法 区间排序问题 SJTU OJ 1360 偶像丁姐的烦恼
    【算法学习笔记】50.字符串处理 SJTU OJ 1361 丁姐的周末
    【算法学习笔记】49.暴力穷举 BFS 剪枝 SJTU OJ 1357 相邻方案
    【算法学习笔记】48.递归/显式栈 SJTU OJ 1358 分割树
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10693999.html
Copyright © 2020-2023  润新知