AC自动机+高斯消元 hdu 5955 Guessing the Dice Roll 16沈阳icpc
在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; }