AC自动机+高斯消元 hdu 5955 Guessing the Dice Roll 16沈阳icpc

試著忘記壹切 提交于 2020-02-16 09:37:37

在AC自动机上,目标节点建立xi = 1的方程,非目标节点建立xi = 0 的方程,其余节点根据Trie树Fail数组转移,建立 xi = ∑ aj * x[i->j] 然后sz个方程,sz个未知数,解得x0,即为从原始状态(游戏开始)到 第i人胜出的概率。 利用高斯消元解方程x0

代码

#include <bits/stdc++.h>
const long long mod = 1e9+7;
const double ex = 1e-10;
const int maxn = 205;
#define inf 0x3f3f3f3f
using namespace std;
int sgn(double x){
    if (x > ex) return 1;
    if ( x < -ex) return -1;
    return 0;
}
struct Trie{
    int ch[maxn][10];
    int last[maxn];
    int val[maxn];
    int f[maxn];
    double gauss[150][150];
    int vis[150];
    int now;
    int sz;
    Trie() {
        sz = 1;
        memset(ch[0],0,sizeof(ch[0]));
    }
    void init(){
        sz = 1;
        memset(ch,0,sizeof(ch));
        memset(val,0,sizeof(val));
        memset(f,0,sizeof(f));
        memset(last,0,sizeof(last));
    }
    void insert(int a[],int l,int v){
        int u = 0;
        for (int i = 0; i<l; i++){
            int c = a[i];
            if (!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = v;
    }
    void getFail(){
        queue <int> q;
        for (int c = 1;c<=6;c++){
            int u = ch[0][c];
            if (u){
                f[u] = 0;
                q.push(u);
                last[u] = 0;
            }
        }
        while (!q.empty()){
            int r = q.front();q.pop();
            for (int c = 1; c <=6 ; 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];
                last[u] = val[f[u]] ? f[u] : last[f[u]];
            }
        }
    }
    void dfs(int u){
        vis[u] = 1;
        gauss[u][u] = 1;
        if (val[u]){
            if (val[u] == now)
                gauss[u][sz] = -1;
            else
                gauss[u][sz] = 0;
            return;
        }
        for (int i = 1; i<=6 ;i++){
            gauss[u][ch[u][i]] += -1.0/6.0;
            if (!vis[ch[u][i]]) dfs(ch[u][i]);
        }
    }
    double Gauss(){
        int n = sz-1;
        for (int i = n ; i >= 1; i--){ //enumerate the ith cancellation
            int tmp;
            for (tmp = i ; tmp >= 0; tmp--){
                if (sgn(gauss[tmp][i]) != 0) break;
            }
            for (int j = 0 ; j <= tmp - 1 ; j++){
                double x = - gauss[j][i]/gauss[tmp][i];
                for (int t = 0 ; t <= sz ; t++)
                    gauss[j][t] = gauss[j][t] + x * gauss[tmp][t];
            }
            swap(gauss[tmp],gauss[i]);
        }
        return -gauss[0][sz]/gauss[0][0];
    }
    double getans(int x){
        now = x;
        memset(gauss,0,sizeof(gauss));
        memset(vis,0,sizeof(vis));
        dfs(0);
        double ans = Gauss();
        return ans;
    }
}Tri;
int main()
{
    int T;
    cin >> T;
    while (T--){
        int N,L;
        cin >> N >> L;
        Tri.init();
        for (int i = 1; i<=N; i++){
            int a[20];
            for (int j = 0 ; j<L ; j++){
                cin >> a[j];
            }
            Tri.insert(a,L,i);
        }
        Tri.getFail();
        for (int i = 1; i<=N; i++){
            printf("%.6f%c",Tri.getans(i),i==N?'\n':' ');
        }
    }
    return 0;
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!