zoukankan      html  css  js  c++  java
  • bzoj1444

    1444: [Jsoi2009]有趣的游戏

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 1191  Solved: 422
    [Submit][Status][Discuss]

    Description

    Input

    注意 是0<=P

    Output

    Sample Input


    Sample Output


    HINT

     30%的数据保证, n ≤ 2. 50%的数据保证, n ≤ 5. 100%的数据保证, n , l, m≤ 10.

    Source

    要省选了 好慌啊 我什么都不会啊 只会抄答案啊 

    抄了个答案 并不是很懂...

    为什么我的ac自动机不对,找了个模板才对...

    为什么不可以直接高斯消元啊...

    先建立ac自动机,然后我们有了张trie图,trie图是由trie树和fail指针组成的。

    那么我们求的就是那些单词末尾的点走到的概率。trie图是一张有向有环图,那么我们不能直接dp...就得用高斯消元解方程。

    但是为什么不可以直接解啊...等待填坑 一份抄来的代码

    upd:2018.2.26

    再次做了一遍,当年naive

    trie图本身是ac自动机的正确形式,没有trie图优化不叫ac自动机

    trie图是一张有向图,自然可以用高斯消元解方程完成

    可惜不能直接设概率,因为根节点已经经过,经过的概率是1,但是可能会再次经过,这样概率就大于1了。

    于是我们设期望,每个点期望走过几次,这样每个节点的终止节点经过的期望次数就是概率,因为不可能经过两次一个终止节点。

    那么我们可以得出方程$x_i =  x_0 * P_{0, i} + x_1 * P_{1, i} + ... + x_{cnt + 1} * P_{cnt + 1, i}$

    然后解方程就好了 

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 110;
    const double eps = 1e-8;
    int n, m, l, root, size, fail;
    int q[N], pos[N];
    double p[N], a[N][N];
    namespace ac 
    {
        struct data {
            int danger, fail; 
            int c[30];
        } t[N];
        void ins(char s[], int id)
        {
            int now = root;
            for(int i = 0; i < l; ++i)
            {
                if(!t[now].c[s[i] - 'A']) t[now].c[s[i] - 'A'] = ++size;
                now = t[now].c[s[i] - 'A'];
            }
    //        printf("now=%d
    ", now);
            t[now].danger = 1; pos[id] = now;
        } 
        void get_fail()
        {
            int l = 1, r = 0;
            for(int i = 0; i < m; ++i) if(t[0].c[i]) q[++r] = t[0].c[i];
            while(l <= r) {
                int u=q[l++];
                t[u].danger |= t[t[u].fail].danger;
                for(int i=0; i<m; i++) {
                    int &v = t[u].c[i];
                    if(!v) v = t[t[u].fail].c[i];
                    else t[v].fail = t[t[u].fail].c[i], q[++r]=v;
                }
            }
        }
    } using namespace ac;
    namespace gauss 
    {
        void build()
        {
            a[0][size + 1] = -1.0;
            for(int i = 0; i <= size; ++i) 
            {
                a[i][i] = -1.0;
                if(t[i].danger) continue;
                for(int j = 0; j < m; ++j) 
                {
    //                printf("i=%d child=%d
    ", i, t[i].c[j]);
                    a[t[i].c[j]][i] += p[j];
                }
            }
        }
        void Gauss()
        {
            for(int now = 0; now <= size; ++now)
            {
                int x = now;
                for(int i = now; i <= size; ++i) if(abs(a[i][now]) > abs(a[x][now]) ) x = i;
                for(int i = 0; i <= size + 1; ++i) swap(a[x][i], a[now][i]);
                double t = a[now][now];
                for(int i = now; i <= size + 1; ++i) a[now][i] /= t;
                for(int i = 0; i <= size; ++i) if(i != now)
                {
                    double t = a[i][now];
                    for(int j = now; j <= size + 1; ++j) a[i][j] -= a[now][j] * t;
                }
            }
        }
    }
    int main()
    {
        using namespace gauss;
        scanf("%d%d%d", &n, &l, &m);
        for(int i = 0; i < m; ++i) 
        {
            double a, b; scanf("%lf%lf", &a, &b);
            p[i] = a / b; if(fabs(p[i]) < eps) ++fail;
        }
        if(fail == m) 
        {
            for(int i = 1; i <= n; ++i) puts("0.00");
            return 0;
        }
        for(int i = 1; i <= n; ++i)
        {
            char s[N]; scanf("%s", s);
            ins(s, i);
        }
        get_fail();
        build(); 
        Gauss();
        for(int i = 1; i <= n; ++i) 
        {
            double t = a[pos[i]][size + 1];
            if(fabs(t) < eps) puts("0.00"); else printf("%.2f
    ", t); 
        }
        return 0;
    } 
  • 相关阅读:
    What is systemvolumeinformation? delete it?
    What is "found.000" ? How to deal with it?
    install Mac OS on Vmware
    字符串数组全排列
    Hadoop开发相关问题
    String直接赋值和使用new的区别
    输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的
    括号匹配问题
    预编译语句
    两个有序单链表合并成一个有序单链表的java实现
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6711511.html
Copyright © 2011-2022 走看看