首页 > 代码库 > bzoj1444

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...就得用高斯消元解方程。

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

#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\n", 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\n", 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\n", t); 
    }
    return 0;
} 

 

bzoj1444