码迷,mamicode.com
首页 > 其他好文 > 详细

「UVA 1358」「LA 3490」Generator

时间:2020-07-12 12:33:41      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:次方   code   uva   int   script   wap   generator   自动   else   

Description

给定一个字符串 \(S\) 以及整数 \(n\),现在生成一个字符串 \(T\),每次可以等概率地随机选取大写字母的前 \(n\) 个并加到 \(T\) 的末尾。

\(T\) 中某个字串为 \(S\) 时停止该过程。

\(T\) 的期望长度。

多组数据,不超过 10 组。

Hint

  • \(1\le n\le 26\)
  • \(1\le |S| \le 15\)

Solution

先对给定串 \(S\) 建出一个状态转移图(即 Trie 图,可以直接使用构造 AC 自动机的算法)。

\(E(x)\) 为状态 \(x\) 到结束状态 \(F\) 的期望转移次数。

那么对于终状态 \(F\),显然 \(E(F) = 0\)

对于其他状态 \(x\),则有 \(E(x) = \dfrac{1}{n} \sum\limits_{c= 1} ^n E(\delta(x, c)) + 1\),即所有下一个状态都需要走一步。

然后…… dp?不幸的是这并不是一个 DAG,是无法直接 dp 的。

不过我们可以根据这些式子构造出 \(|Q|\) (状态集大小)个一次方程,这样就可以使用 高斯消元 解出方程,答案即为 \(E(t_0)\)

Code

#include <cmath>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;
typedef long long ll;
typedef vector<long double> vec;
typedef vector<vec> mat;
const int N = 17;
const int MaxS = 26;

long double gauss(mat x) {
	int n = x.size();
	for (register int i = 0; i < n; i++) {
		int r = i;
		while (r < n && !x[r][i]) ++r;
		if (r != i) swap(x[r], x[i]);
		for (register int j = i + 1; j < n; j++) {
			ll f = x[j][i] / x[i][i];
			for (register int k = i; k <= n; k++)
				x[j][k] -= f * x[i][k];
		}
	}
	for (register int i = n - 1; ~i; i--) {
		for (register int j = i + 1; j < n; j++)
			x[i][n] -= x[j][n] * x[i][j];
		x[i][n] /= x[i][i];
	}
	return x[0][n];
}

int sigma;
struct DFA {
	int ch[N][MaxS];
	int fail[N], total;
	
	void init(char* s) {
		for (int x = 0; *s; s++) {
			int c = *s - ‘A‘;
			x = ch[x][c] = ++total;
		}
		
		queue<int> Q; Q.push(1);
		while (!Q.empty()) {
			int x = Q.front(); Q.pop();
			for (register int c = 0; c < sigma; c++)
				if (ch[x][c]) {
					Q.push(ch[x][c]);
					fail[ch[x][c]] = ch[fail[x]][c];
				} else ch[x][c] = ch[fail[x]][c];
		}
	}
	
	void reset() {
		*this = DFA();
	}
	
	mat construct() {
		int n = total;
		mat E(n + 1, vec(n + 2));
		
		for (register int i = 0; i < n; i++) {
			E[i][i] += sigma;
			for (register int j = 0; j < sigma; j++)
				E[i][ch[i][j]] -= 1;
			E[i][n + 1] = sigma;
		}
		E[n][n] = 1, E[n][n + 1] = 0;
		
		return E;
	}
} dfa;

char s[N];
void solve() {
	scanf("%d%s", &sigma, s);
	
	dfa.reset();
	dfa.init(s);
	
	mat E = dfa.construct();
	
	printf("%lld\n", (long long)(gauss(E) + 0.5));
}

signed main() {
	int T; cin >> T;
	for (register int i = 1; i <= T; i++) {
		printf("Case %d:\n", i);
		solve();
		if (T != i) puts("");
	}
}

「UVA 1358」「LA 3490」Generator

标签:次方   code   uva   int   script   wap   generator   自动   else   

原文地址:https://www.cnblogs.com/-Wallace-/p/13287285.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!