您的位置:首页 > 其它

HDOJ 2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)

2015-10-23 08:53 381 查看


考研路茫茫——单词情结

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4501    Accepted Submission(s): 1361


Problem Description

背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。

一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如"ab",放在单词前一般表示"相反,变坏,离去"等。

于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。

比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为

(2个) aa,ab,

(26个)aaa,aab,aac...aaz,

(26个)aba,abb,abc...abz,

(25个)baa,caa,daa...zaa,

(25个)bab,cab,dab...zab。

这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。

 

Input

本题目包含多组数据,请处理到文件结束。

每组数据占两行。

第一行有两个正整数N和L。(0<N<6,0<L<2^31)

第二行有N个词根,每个词根仅由小写字母组成,长度不超过5。两个词根中间用一个空格分隔开。

 

Output

对于每组数据,请在一行里输出一共可能的单词数目。

由于结果可能非常巨大,你只需要输出单词总数模2^64的值。

 

Sample Input

2 3
aa ab
1 2
a

 

Sample Output

104
52

 

Author

linle

 

Recommend

lcy   |   We have carefully selected several similar problems for you:  3341 2296 2825 3247 2457

题解: 我们可以首先算出长度不超过L的单词总数是多少, 然后算出长度不超过L不包含词根的总数是多少, 然后相减就可以了, 需要注意的地方, 因为是对2^64取模, 所以我们定义一个unsigned long long 就可以了, 会实现自动取模.

 好了, 我们首先来做第一步,  长度不超过L的单词总数是多少呢? 肯定是26^1 + 26^2 + 26^3 + ...... 26^L, 可是如何去求呢,如果我们算出它的等比数列来,然后求逆元取模,是错误的,因为2^64不是质数,所以不符合费马小定理,是错误的.

我们可以这样来做

设 f(n) = 26^1 + 26^2 + 26^3 + ...... 26^n;

则,当n为奇数的时候f(n) = f(n/2) + f(n/2) * (a^(n/2)) + 26^n

       当n为偶数的时候f(n) = f(n/2) + f(n/2) * (a^(n/2))

这样,二分递归求解即可.

然后做第二步,如何求长度不超过L的不包含词根的单词总数

求长度为x的不包含任何词根的单词数,poj2778就是这样的一个题http://blog.csdn.net/lost_in_wine/article/details/49300931

同样是用AC自动机+矩阵快速幂来实现,然后我们在用上式的方法来求不超过L的不包含词根的单词数.

这样,这个问题就解决了.

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int N = 31;
const int L = 26;
typedef unsigned long long LL;

struct Matrix{
LL ary

;
int l;
void clear() {memset(ary, 0, sizeof(ary));}
Matrix() {clear();}
};

const Matrix operator*(const Matrix & A, const Matrix & B) {
Matrix t;
t.l = A.l;
for (int i = 0; i < t.l; ++i)
for (int j = 0; j < t.l; ++j)
for (int k = 0; k < t.l; ++k)
t.ary[i][j] += A.ary[i][k] * B.ary[k][j];
return t;
}

const Matrix operator+(const Matrix & A, const Matrix & B) {
Matrix t;
t.l = A.l;
for (int i = 0; i < t.l; ++i)
for (int j = 0; j < t.l; ++j)
t.ary[i][j] = A.ary[i][j] + B.ary[i][j];
return t;
}

struct Trie{
int next
[L], fail
;
bool vis
;
int total, root;
Matrix mt;

int new_node() {
for (int i = 0; i < L; ++i)
next[total][i] = -1;
vis[total] = false;
return total++;
}

void init() {
mt.clear();
total = 0;
root = new_node();
}

void insert(char *str) {
int cur = root;
while (*str) {
int idx = *str - 'a';
if (next[cur][idx] == -1)
next[cur][idx] = new_node();
cur = next[cur][idx];
++str;
}
vis[cur] = true;
}

void build() {
queue<int> q;
q.push(root);
fail[root] = -1;

while (!q.empty()) {
int cur = q.front();
q.pop();
if (fail[cur] != -1 && vis[fail[cur]] == true)
vis[cur] = true;
for (int i = 0; i < L; ++i) {
if (next[cur][i] == -1)
next[cur][i] = fail[cur] == -1 ? root : next[fail[cur]][i];
else {
fail[next[cur][i]] = fail[cur] == -1 ? root : next[fail[cur]][i];
q.push(next[cur][i]);
}
}
}

mt.l = total;
for (int i = 0; i < total; ++i)
for (int j = 0; j < L; ++j)
if (vis[next[i][j]] == false)
++mt.ary[i][next[i][j]];
}

}tree;

Matrix quick_pow(Matrix mt, LL n) {
Matrix ans, tmp = mt;
ans.l = mt.l;
for (int i = 0; i < mt.l; ++i) ans.ary[i][i] = 1;
while (n) {
if (n & 1)
ans = ans * tmp;
tmp = tmp * tmp;
n >>= 1;
}
return ans;
}

Matrix pow_M(Matrix mt, LL n) {
if (n == 1) return mt;
Matrix ans;
Matrix tmp;
ans.l = tmp.l = mt.l;
for (int i = 0; i < mt.l; ++i) tmp.ary[i][i] = 1;
if (n & 1)
ans = ans + quick_pow(mt, n);
return ans + (quick_pow(mt, n / 2) + tmp) * pow_M(mt, n / 2);
}

int main() {
LL n, l;
while (~scanf("%llu%llu", &n, &l)) {
tree.init();
char str[10];
for (int i = 0; i < n; ++i) {
scanf("%s", str);
tree.insert(str);
}
tree.build();
LL total, ans;
Matrix mt;
total = 0, ans = 0;
mt = pow_M(tree.mt, l);
for (int i = 0; i < mt.l; ++i)
ans += mt.ary[0][i];
mt.l = 1;
mt.ary[0][0] = 26;
mt = pow_M(mt, l);
total = mt.ary[0][0];
printf("%llu\n", total - ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: