Magic boy Bi Luo with his excited string problem
题意:
给出<=15个字母串,每个串不超过10个字符,然后一个人开始写字母,每次随机写一个字母,直到出现给出的任意一个串,然后就停止,问写的长度的期望,答案mod 1e9+7。
思路:
总共150个字母比较少,用ac自动机建立转移矩阵,
dp[i]
表示从状态i出发写的期望,然后套高斯消元解方程。
每个状态可以写一个方程:
dp[i]=126dp[son[i][0]]+126dp[son[i][1]]+⋯+126dp[son[i][25]]+1
然后乘个26解决分数,移项过去就变成矩阵形式了。
//
// main.cpp
// 1025
//
// Created by 翅膀 on 16/9/16.
// Copyright © 2016年 kg20006. All rights reserved.
//
#include <iostream>
#include <queue>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <string.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int N = 155;
ll qpow(ll a, ll k) {
ll res = 1;
a = (a%mod+mod)%mod;
while(k) {
if(k&1) res = (res*a)%mod;
a = (a*a)%mod;
k >>= 1;
}
return res;
}
ll a[N][N];
ll x[N];
void swapcol(int x, int y, int row){
for(int i = 0; i < row; ++i){
swap(a[i][x], a[i][y]);
}
}
void getans(int row, int col){
for(int i = col-1; i >= 0; --i){
ll tmp = a[i][col];
for(int j = i+1; j < col; ++j){
tmp = ((tmp-a[i][j]*x[j]%mod)%mod+mod)%mod;
}
ll X = tmp*qpow(a[i][i], mod-2)%mod;
x[i] = X;
}
}
int Gauss(int row, int col){
int r = 0, c = 0;
for(; r < row && c < col; ++r, ++c){
int mx = r;
for(int i = r+1; i < row; ++i){
if(abs(a[i][c]) > abs(a[mx][c])) mx = i;
}
if(mx != r) swap(a[mx], a[r]);
if(a[r][c] == 0){ r--; continue; }
for(int i = r+1; i < row; ++i){
if(!a[i][c]) continue;
ll tmp1 = a[r][c], tmp2 = a[i][c];
for(int j = c; j <= col; ++j){
a[i][j] = (a[i][j]*tmp1 - a[r][j]*tmp2)%mod;
if(a[i][j] < 0) a[i][j] += mod;
}
}
}
for(int i = r; i < row; ++i){
if(a[i][col]) return -1;
}
int free_x = col-r; //自由元的个数
for(int i = 0, j; i < col && i < row; ++i){
if(!a[i][i]){
for(j = i+1; j < col; ++j) if(a[i][j]) break;
if(j < col) swapcol(i, j, row);
}
}
getans(row, col);
return free_x;
}
struct Trie{
static const int MX = 155;
int son[MX][26], fail[MX], end[MX];
int root, alloc;
int newnode(){
memset(son[++alloc], 0, sizeof(son[alloc]));
end[alloc] = 0, fail[alloc] = 0;
return alloc;
}
void init(){
alloc = 0;
root = newnode();
}
void insert(char *s) {
int p = root;
for(int i = 0; s[i]; ++i) {
if(son[p][s[i]-'a'] == 0) son[p][s[i]-'a'] = newnode();
p = son[p][s[i]-'a'];
}
end[p] = 1;
}
void build() {
queue<int>q;
for(int i = 0; i < 26; ++i) {
if(son[root][i] == 0) son[root][i] = root;
else fail[son[root][i]] = root, q.push(son[root][i]);
}
while(!q.empty()){
int u = q.front(); q.pop();
if(end[fail[u]]) end[u] = 1;
for(int i = 0; i < 26; ++i) {
if(son[u][i] == 0) son[u][i] = son[fail[u]][i];
else fail[son[u][i]] = son[fail[u]][i], q.push(son[u][i]);
}
}
}
ll DP(){
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
for(int i = 1; i <= alloc; ++i){
if(end[i]){
a[i-1][i-1] = 1;
a[i-1][alloc] = 0;
continue;
}
a[i-1][i-1] = 26;
for(int j = 0; j < 26; ++j) {
a[i-1][son[i][j]-1] -= 1;
}
a[i-1][alloc] = 26;
}
Gauss(alloc, alloc);
return x[0];
}
}ac;
char s[25];
int main(int argc, const char * argv[]) {
int T, ca = 1;
scanf("%d", &T);
while(T--) {
ac.init();
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
scanf("%s", s);
ac.insert(s);
}
ac.build();
printf("Case #%d: %lld\n", ca++, ac.DP());
}
return 0;
}