HDU 5955 Guessing the Dice Roll
HDU 5955 Guessing the Dice Roll
2016 ACM/ICPC 亚洲区沈阳站
题意
- 有\(N\le 10\)个人,每个猜一个长度为\(L \le 10\)的由\(1-6\)构成的序列,保证序列两两不同。
- 不断地掷骰子,直到后缀与某人的序列匹配,则对应的人获胜。
- 求每个人获胜的概率。
思路
- 显然,涉及的序列最多100个,用ac自动机构出这些状态,计算状态之间的转移概率。
- 记增量矩阵为\(A\)(即终状态不再计算转移到自身的概率),答案为\(b\),初始序列为\(x\),则$$b=\sum_{i=1}{\infty}{Ai}x$$
- 显然矩阵\(A\)是收敛的,所以式子转化为$$b=(I-A)^{-1}x\x=(I-A)b$$
- 高斯消元求解即可,注意精度问题。
- 另一种解法,构造包括终止状态转移到自身的矩阵,结合快速幂,可以卡过去(注意指数取\(2^i\)形式以减少常数)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define sz(x) ((int)(x).size())
#define rep(i,l,r) for(int i=(l);i<(r);++i)
//-------head-------
const int N = 1007;
const double EPS = 1e-12;
int n, l, a[N], id[N];
template<int V>
struct AhoCorasick {
int dep[V];
int siz, lnk[V], que[V], trie[V][7];
int addNode(int _dep) {
memset(trie[siz], 0, sizeof(trie[siz]));
lnk[siz] = 0, dep[siz] = _dep;
return siz++;
}
void init() {
siz = 0;
addNode(0);
}
int add(const int *a, int n) {
int p = 0;
rep(i, 0, n)
{
int x = a[i];
if (!trie[p][x])
trie[p][x] = addNode(i + 1);
p = trie[p][x];
}
return p;
}
void build() {
que[0] = 0;
for (int h = 0, t = 1; h < t; ++h) {
int v = que[h];
rep(c, 1, 7)
if (trie[v][c]) {
int u = lnk[v];
while (u && !trie[u][c])
u = lnk[u];
lnk[trie[v][c]] = !v ? 0 : trie[u][c];
que[t++] = trie[v][c];
} else {
trie[v][c] = trie[lnk[v]][c];
}
}
}
};
template<int N>
struct Gauss {
double a[N][N];
void init(int n, int m) {
rep(i, 0, n)
rep(j, 0, m)
a[i][j] = 0;
}
void run(int n, int m) {
int row, col;
for (row = col = 0; row < n && col < m; ++row, ++col) {
int mxr = row;
rep(i, row + 1, n)
if (fabs(a[i][col]) > fabs(a[mxr][col]))
mxr = i;
if (fabs(a[mxr][col]) < EPS) {
--row;
continue;
}
if (mxr != row)
swap(a[row], a[mxr]), swap(id[row], id[mxr]);
rep(i, 0, n)
if (i != row && fabs(a[i][col]) > EPS)
for (int j = m; j >= col; --j)
a[i][j] -= a[row][j] * a[i][col] / a[row][col];
}
}
void out(int n, int m) {
rep(i, 0, n) {
rep(j, 0, m)
printf("%lf ", a[i][j]);
puts("");
}
}
};
AhoCorasick<N> ac;
Gauss<N> ga;
double ans[N];
int main() {
int T;
scanf("%d", &T);
rep(cas, 0, T) {
scanf("%d%d", &n, &l);
ac.init();
memset(id, -1, sizeof(id));
rep(i, 0, n) {
rep(j, 0, l)
scanf("%d", &a[j]);
id[ac.add(a, l)] = i;
}
ac.build();
ga.init(ac.siz, ac.siz + 1);
rep(i, 0, ac.siz) {
if (~id[i]) {
// ga.a[i][i] = 0;
} else {
rep(j, 1, 7)
ga.a[ac.trie[i][j]][i] += 1.0 / 6.0 ;
}
}
rep(i, 0, ac.siz)
ga.a[i][i] -= 1.0;
ga.a[0][ac.siz] = -1.0;
// ga.out(ac.siz, ac.siz + 1);
ga.run(ac.siz, ac.siz);
// puts("");
// ga.out(ac.siz, ac.siz + 1);
rep(i, 0, ac.siz)
if (~id[i]) {
ans[id[i]] = ga.a[i][ac.siz] / ga.a[i][i];
}
rep(i, 0, n) {
if (i)
putchar(' ');
printf("%.6lf", fabs(ans[i]));
}
puts("");
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步