LA3490 Generator(KMP + 高斯消元)
题意
一开始给你一个长为 \(S\) 的字符串。
从空串开始,不断在后面添加一个 \([A, A + n]\) 的一个字符。
第一次包含 \(S\) 的时候会停止添加。问期望的添加次数。
有 \(T\) 组数据。
\(T \le 10, |S| \le 12, n \le 26\)
题解
单模板匹配的直接用 \(\mathrm{KMP}\) 就可以了。
那么我们枚举 \(S\) 第 \(i\) 位 \(S_i\) ,然后枚举当前这位填的数 \(c\) ,那么就会转移到 \(S_{\delta (i, c)}\) 。(这个过程和普通匹配跳 \(fail\) 是一样的)
然后是期望,我们考虑倒推。令 \(dp_i\) 为当前匹配了前 \(i\) 位期望添加的字符才能匹配完。
那么显然有如下的转移:
- \(i = |S|: dp_i = 0\)
 - \(i \not = |S|: dp_i = (\sum_{c} dp_{\delta(i, c)}) + 1\)
 
这样转移显然会出环。这种 \(dp\) 直接上高斯消元即可。
但是如果直接用 long double 做的话,虽然样例过得了,但是精度会被卡掉。
那有什么好办法吗?答案看起来一定是整数,那么我们显然想用 long long 解决。
前面消成上三角的时候,除的东西不能保证整除。
其中一种解决办法是用几个模数进行模意义下的消元,然后 \(CRT\) 合并即可。但是不太好写。
后来问了 zhou888 ,它告诉我一个神奇的做法,每次消去一行的时候,辗转相除,不断除掉共有的最多的那个就行了。
虽然多了个 \(\log n\) 的复杂度,但是确实好写啊。。。
然后复杂度就是 \(O(|S| \times n + |S|^3 \log n)\) 的。
代码
具体实现可以见代码。
#include <bits/stdc++.h>
#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
using namespace std;
typedef long long ll;
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }
inline int read() {
	int x(0), sgn(1); char ch(getchar());
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
	for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
	return x * sgn;
}
void File() {
#ifdef zjp_shadow
	freopen ("3490.in", "r", stdin);
	freopen ("3490.out", "w", stdout);
#endif
}
const int N = 14;
ll Mat[N][N];
void Gauss(int n) {
	For (i, 1, n) {
		For (j, i + 1, n) {
			ll a = Mat[i][i], b = Mat[j][i];
			while (b) {
				ll tmp = a / b; a %= b; swap(a, b); swap(Mat[i], Mat[j]);
				For (k, i, n + 1) Mat[j][k] -= tmp * Mat[i][k];
			}
		}
	}
	Fordown (i, n, 1) {
		For (j, i + 1, n)
			Mat[i][n + 1] -= Mat[i][j] * Mat[j][n + 1], Mat[i][j] = 0;
		Mat[i][n + 1] /= Mat[i][i]; Mat[i][i] = 1;
	}
}
int n, fail[N];
void Get_Fail(char *S) {
	For (i, 2, strlen(S + 1)) {
		int j = fail[i - 1];
		while (j && S[i] != S[j + 1]) j = fail[j];
		fail[i] = S[i] == S[j + 1] ? j + 1 : 0;
	}
}
char str[N];
int main () {
	File();
	For (cases, 1, read()) {
		int alpha = read(); scanf ("%s", str + 1);
		int n = strlen(str + 1);
		Get_Fail(str); Set(Mat, 0);
		Mat[n + 1][n + 1] = alpha;
		For (i, 0, n - 1) {
			Mat[i + 1][i + 1] = Mat[i + 1][n + 2] = - alpha;
			Rep (j, alpha) {
				char cur = j + 'A';
				int pos = i;
				while (pos && str[pos + 1] != cur) pos = fail[pos];
				if (str[pos + 1] == cur) ++ pos;
				Mat[i + 1][pos + 1] += 1;
			}
		}
		Gauss(n + 1);
		printf ("Case %d:\n", cases);
		printf ("%lld\n", Mat[1][n + 2]);
		if (cases < casesend) putchar('\n');
	}
	return 0;
}
												
											LA3490 Generator(KMP + 高斯消元)的更多相关文章
- [BZOJ4820]硬币游戏 KMP+高斯消元
		
4820: [Sdoi2017]硬币游戏 Time Limit: 10 Sec Memory Limit: 128 MB Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的 ...
 - UVA 1358 - Generator(dp+高斯消元+KMP)
		
UVA 1358 - Generator option=com_onlinejudge&Itemid=8&page=show_problem&category=524& ...
 - bzoj 4820: [Sdoi2017]硬币游戏【kmp+高斯消元】
		
有点神,按照1444的做法肯定会挂 注意到它的概率是相同的,所以可以简化状态 详见http://www.cnblogs.com/candy99/p/6701221.html https://www.c ...
 - [Sdoi2017]硬币游戏 [高斯消元 KMP]
		
[Sdoi2017]硬币游戏 题意:硬币序列,H T等概率出现,\(n \le 300\)个人猜了一个长为$ m \le 300$的字符串,出现即获胜游戏结束.求每个人获胜概率 考场用了[1444: ...
 - BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)
		
BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...
 - [BZOJ4820][SDOI2017]硬币游戏(高斯消元+KMP)
		
比较神的一道题,正解比较难以理解. 首先不难得出一个(nm)^3的算法,对所有串建AC自动机,将在每个点停止的概率作为未知数做高斯消元即可. 可以证明,AC自动机上所有不是模式串终止节点的点可以看成一 ...
 - BZOJ4820 SDOI2017硬币游戏(概率期望+高斯消元+kmp)
		
容易想到的做法是建出AC自动机,高斯消元.然而自动机上节点数量是nm的. 注意到我们要求的变量只有n个,考虑将其他不用求的节点合并为一个变量.这个变量即表示随机生成一个串,其不包含任何一个模板串的概率 ...
 - UVALive - 3490 Generator (AC自动机+高斯消元dp)
		
初始有一个空串s,从前n个大写字母中不断随机取出一个字母添加到s的结尾,出现模式串t时停止,求停止时s的长度期望. 这道题解法不唯一,比较无脑的方法是对模式串t建一个单串AC自动机,设u为自动机上的一 ...
 - BZOJ 4820 [Sdoi2017]硬币游戏 ——期望DP 高斯消元
		
做法太神了,理解不了. 自己想到的是建出AC自动机然后建出矩阵然后求逆计算,感觉可以过$40%$ 用一个状态$N$表示任意一个位置没有匹配成功的概率和. 每种匹配不成功的情况都是等价的. 然后我们强制 ...
 
随机推荐
- 如何在Anaconda中把python环境更新更高版本
			
把Anaconda中的python从3.5.5更新到3.6版本,不想卸载重新安装.办法如下: 开始->Anaconda Promot 在Anaconda Promot中,输入: conda up ...
 - 出题人的女装(牛客练习赛38题B) (概率+分式运算)
			
链接:https://ac.nowcoder.com/acm/contest/358/B来源:牛客网 出题人的女装 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
 - 【问题解决方案】Git bash进入多层子目录问题(通配符问题留坑)
			
cd进入指定路径下:cd 斜杠 斜杠 方法一: 1- 撇丿,不是"那",盘符前面要加上 / (d盘前面也加,不加也行) 2- 路径名不区分大小写 3- 不用空格 4- 如果目录名中 ...
 - Docker存储驱动Device Mapper,Overlay,AUFS
			
Docker存储驱动之Device Mapper简介 - BookShu - 博客园https://www.cnblogs.com/styshoo/p/6528762.html Docker存储驱动之 ...
 - MYSQL业务数据简单脱敏方案
			
removesensitiveinformationplan.sh #!/bin/sh #!在模拟库上运行如下脚本 #!生产库crm-db #!模拟库crm-mock #!.备份生产库 mysqldu ...
 - redux模块化demo
			
store.js 在redux中 store 是唯一的. import {createStore} from 'redux'; import reducer from './reducer' // 引 ...
 - 【学亮IT手记】mysql创建/查看/切换数据库
			
--创建数据库 create database web_test1 CHARACTER set utf8; --切换数据库 use web_test1; --查看当前使用的数据库 select DAT ...
 - 国内的go get问题的解决
			
在国内采用go get有时会下载不到一些网站如golang.org的依赖包. 方法1(亲测有效): gopm 代替go 下载第三方依赖包可以采用gopm从golang.org一些镜像网站上下载. 注意 ...
 - 关于@Param
			
1,使用@Param注解 当以下面的方式进行写SQL语句时: @Select("select column from table where userid = #{userid} " ...
 - C# 将当前应用程序写入到注册表开机启动项中
			
在使用C#进行应用程序的开发过程中,经常有一个需求就是让应用程序开机后自动启动,这个是一个很常见的需求,最常规的做法(这里以Win7操作系统为例),打开:开始=>所有程序=>启动文件夹(路 ...