HDU 2243 考研路茫茫――单词情结
题意:给定一些词根,如果一个单词包含有词根,则认为是有效的。现在问长度不超过L的单词里面,有多少有效的单词?
思路:这道题和 POJ 2778 是同样的思路。POJ 2778是要找出长度为L的单词里面有多少无效的单词。那么根据同样的方法构造矩阵,然后所有无效的单词个数为 A + A^2 + ... + A^l 个。而所有单词的个数为26 + 26^2 + … + 26^l 个。两个减一下即为答案。
矩阵连乘求和:I + A^2 + A^3 + ... + A^n
1. 构造矩阵
|A I|
|0 I|
2. 分治法
n为偶数,例如n = 6时
A + A^2 + A^3 + A^4 + A^5 + A^6 = (A + A^2 + A^3) + A^3*(A + A^2 + A^3)
n为奇数,例如n = 5时
A + A^2 + A^3 + A^4 + A^5 = (A + A^2) + A^2*(A + A^2) + A^5
代码:
/*
ID: [email protected]
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
typedef unsigned long long ULL;
using namespace std;
const int maxn = 65;
const int maxm = 65;
struct Matrix {
int n, m;
ULL a[maxn][maxm];
void clear() {
n = m = 0;
memset(a, 0, sizeof(a));
}
Matrix operator * (const Matrix &b) const { //实现矩阵乘法
Matrix tmp;
tmp.n = n;
tmp.m = b.m;
for (int i = 0; i < n; i++)
for (int j = 0; j < b.m; j++) tmp.a[i][j] = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (!a[i][j]) continue;
for (int k = 0; k < b.m; k++)
tmp.a[i][k] += a[i][j] * b.a[j][k];
}
return tmp;
}
Matrix operator + (const Matrix &b) const {
Matrix tmp;
tmp.n = n;
tmp.m = m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
tmp.a[i][j] = a[i][j] + b.a[i][j];
return tmp;
}
void Copy(const Matrix &b) {
n = b.n, m = b.m;
for (int i = 0; i < n; i++)
for(int j = 0; j < m; j++) a[i][j] = b.a[i][j];
}
void unit(int sz) {
n = m = sz;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) a[i][j] = 0;
a[i][i] = 1;
}
}
} A, res;
const int maxnode = 30 * 26;
const int charset = 26;
struct ACAutomaton {
int ch[maxnode][charset];
int fail[maxnode];
int Q[maxnode];
int val[maxnode];
int sz;
int ID[128];
void init() {
fail[0] = 0;
for (int i = 0; i < charset; i++) ID[i + 'a'] = i;
}
void reset() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void Insert(char* s, int key) {
int u = 0;
for (; *s; s++) {
int c = ID[*s];
if (!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = key;
}
void Construct () {
int *s = Q, *e = Q;
for (int i = 0; i < charset; i++) {
if (ch[0][i]) {
*e++ = ch[0][i];
fail[ch[0][i]] = 0;
}
}
while(s != e) {
int u = *s++;
if (val[fail[u]]) val[u] = 1;
for (int i = 0; i < charset; i++) {
int &v = ch[u][i];
if (v) {
*e++ = v;
fail[v] = ch[fail[u]][i];
} else {
v = ch[fail[u]][i];
}
}
}
}
void work() {
for (int i = 0; i < sz; i++) {
for (int j = 0; j < charset; j++) {
if (!val[i] && !val[ch[i][j]]) {
A.a[ch[i][j]][i]++;
}
}
}
}
} AC;
Matrix Matrix_pow(Matrix A, ll k) {
res.clear();
res.n = res.m = AC.sz;
for (int i = 0; i < AC.sz; i++) res.a[i][i] = 1;
while(k) {
if (k & 1) res.Copy(res * A);
A.Copy(A * A);
k >>= 1;
}
return res;
}
void out() {
for (int i = 0; i < A.n; i++) {
for (int j = 0; j < A.m; j++) {
printf("%2d ", res.a[i][j]);
}
cout << endl;
}
}
Matrix Matrix_Bpow(Matrix A, ll k) {
Matrix ans, I, tmp;
ans.clear();
ans.n = ans.m = A.n;
I.unit(A.n);
tmp.unit(A.n);
while(k > 0) {
if (k & 1) ans.Copy(ans * A + tmp);
tmp.Copy(tmp * (I + A));
A.Copy(A * A);
k >>= 1;
}
return ans;
}
int main () {
int n;
ll l;
char str[10];
AC.init();
while(~scanf("%d%I64d", &n, &l)) {
A.clear();
AC.reset();
for (int i = 0; i < n; i++) {
scanf("%s", str);
AC.Insert(str, 1);
}
int sz = AC.sz;
A.n = A.m = sz;
AC.Construct();
AC.work();
//分治法
res = Matrix_Bpow(A, l + 1);
//out();
/* 构造矩阵
//得到1 + A + A^2 + A^3 + ... + A^l
for (int i = 0; i < sz; i++) A.a[i][i + sz] = A.a[i + sz][i + sz] = 1;
res = Matrix_pow(A, l + 1);
*/
ULL ans = 0;
for (int i = 0; i < sz; i++) ans += res.a[i][0];
ans--;
//得到1 + 26 + 26^2 + ... + 26^l
A.clear();
A.n = A.m = 2;
A.a[0][0] = 26, A.a[0][1] = A.a[1][1] = 1;
A = Matrix_pow(A, l + 1);
ULL tot = A.a[0][1] - 1;
printf("%I64u\n", tot - ans);
}
return 0;
}