当前位置 博文首页 > 文章内容

    「UVA 1358」「LA 3490」Generator

    作者: 栏目:未分类 时间:2020-07-12 11:01:00

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    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("");
    	}
    }