1444: [Jsoi2009]有趣的游戏

1444: [Jsoi2009]有趣的游戏

链接

分析:

  如果一个点回到0号点,那么会使0号点的概率增加,而0号点的概率本来是1,不能增加,所以这题用期望做。

  设$x_i$表示经过i的期望次数,然后初始可以知道$x_0=0$,又因为末尾节点只会经过一次,所以末尾节点的概率就是期望。

  然后建出AC自动机,高斯消元。

  参考sengxian

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 500;
const double eps = 1e-10;
int ch[N][26], val[N], fail[N], id[N], q[N], Index;
int n, L, m;
char s[N];
double A[N][N], p[N];

void Insert(int x) {
    int now = 0;
    for (int i = 0; i < L; ++i) {
        int c = s[i] - 'A';
        if (!ch[now][c]) ch[now][c] = ++Index;
        now = ch[now][c];
    }
    val[now] = 1, id[x] = now;
}
void bfs() {
    int L = 1, R = 0;
    for (int c = 0; c < m; ++c) if (ch[0][c]) q[++R] = ch[0][c];
    while (L <= R) {
        int u = q[L ++]; 
        for (int c = 0; c < m; ++c) {
            int v = ch[u][c];
            if (!v) ch[u][c] = ch[fail[u]][c];
            else {
                fail[v] = ch[fail[u]][c];
                val[v] |= val[fail[v]];
                q[++R] = v;
            }
        }
    }
}
bool Gauss(int n) {
    for (int k = 0; k <= n; ++k) {
        int r = k;
        for (int i = k + 1; i <= n; ++i) if (A[i][k] > A[r][k]) r = k;
        if (r != k) for (int j = 0; j <= n + 1; ++j) swap(A[r][j], A[k][j]);
        for (int i = k + 1; i <= n; ++i) {
            if (fabs(A[i][k]) > eps) {
                double t = A[i][k] / A[k][k];
                for (int j = 0; j <= n + 1; ++j) A[i][j] -= A[k][j] * t;
            }
        }
    }
    for (int i = n; i >= 0; --i) {
        for (int j = i + 1; j <= n; ++j) A[i][n + 1] -= A[j][n + 1] * A[i][j];
        A[i][n + 1] /= A[i][i];
    }
    return 1;
}
int main() {
    n = read(), L = read(), m = read();
    for (int i = 0; i < m; ++i) {
        int u = read(), v = read();
        p[i] = 1.0 * u / v;
    }
    int cnt = 0;
    for (int i = 0; i < n; ++i) {
        scanf("%s", s);
        for (int j = 0; j < L; ++j) 
            if (p[s[j] - 'A'] <= eps) { cnt ++; break; }
        Insert(i);
    }
    if (cnt == n) {
        for (int i = 1; i <= n; ++i) puts("0.00"); return 0;
    }
    bfs();
    A[0][Index + 1] = -1;
    for (int i = 0; i <= Index; ++i) {
        A[i][i] = -1.0;
        if (val[i]) continue;
        for (int c = 0; c < m; ++c) A[ch[i][c]][i] += p[c];
    }
    Gauss(Index);
    for (int i = 0; i < n; ++i) {
        double p = A[id[i]][Index + 1];
        if (fabs(p) <= eps) puts("0.00");
        else printf("%.2lf\n", p);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/10389148.html