hnu 2243 考研路茫茫——单词情结 AC自动机+矩阵冥累加和
这个题目更奇葩。据说是上一个题的加强版。题意是给定M个模式串,然后给定长度L,问不超过L的文本至少含有一个模式的情况的总种数。
还是用模式串建立Trie图,根据Trie图建立起路径长度为1的矩阵M。
总情况数目为26^1+26^2+...+26^L。不含模式串的情况总数为矩阵N = M^1+M^2+M^3
+...+M^L的第一行之和。总情况数目减去不含模式串的情况就是答案。
这里用到了矩阵的一些算法,比如快速冥,还有快速冥求和。但是,我用了操作符重载,最悲剧
的是重载后的操作符没有优先级,而我还当作有优先级的在用,所以悲剧了。。。一直样例都过不
去。。。唉,最后才发现了这个问题。。。写了260行左右的代码,前面的一部分代码可以当作矩
阵操作的模板了。。。Trie图的也不错,过几天估计得打印下来用了。。。
代码如下:
#include <stdio.h>
#include < string.h>
#include <queue>
#include <algorithm>
using namespace std;
typedef unsigned long long INT;
const int MAX_D = 26;
const int MAX_L = 10;
const int MAX_N = 10;
char szPat[MAX_L];
const int MAX_S = 31;
struct Matrix
{
int nSize;
INT nD[MAX_S][MAX_S];
Matrix( int nS)
{
Clear(nS);
}
Matrix& operator = ( const Matrix& m)
{
nSize = m.nSize;
for ( int i = 0; i < nSize; ++i)
{
for ( int j = 0; j < nSize; ++j)
{
nD[i][j] = m.nD[i][j];
}
}
return * this;
}
void Clear( int nS)
{
nSize = nS;
memset(nD, 0, sizeof(nD));
}
void Unit()
{
for ( int i = 0; i < nSize; ++i)
{
for ( int j = 0; j < nSize; ++j)
{
nD[i][j] = (i == j ? 1 : 0);
}
}
}
};
Matrix operator+( const Matrix& A, const Matrix& B)
{
Matrix C(A.nSize);
for ( int i = 0; i < A.nSize; ++i)
{
for ( int j = 0; j < A.nSize; ++j)
{
C.nD[i][j] = A.nD[i][j] + B.nD[i][j];
}
}
return C;
}
Matrix operator*( const Matrix& nA, const Matrix& nB)
{
Matrix nC(nB.nSize);
for ( int i = 0; i < nA.nSize; ++i)
{
for ( int j = 0; j < nA.nSize; ++j)
{
for ( int k = 0; k < nA.nSize; ++k)
{
nC.nD[i][j] += nA.nD[i][k] * nB.nD[k][j];
}
}
}
return nC;
}
Matrix operator^(Matrix B, INT nExp)
{
Matrix ans(B.nSize);
ans.Unit();
while (nExp)
{
if (nExp % 2)
{
ans = ans * B;
}
B = B * B;
nExp >>= 1;
}
return ans;
}
// 求base^1+base^2++base^N
Matrix SumPowMatrix(Matrix& base, INT nN)
{
if (nN == 1)
{
return base;
}
Matrix ans = SumPowMatrix( base, nN / 2);
ans = ans + (( base^(nN / 2)) * ans); // 重载运算符保证不了优先级
if (nN % 2)
{
ans = ans + ( base^nN); // 没优先级啊,必须加括号,查错2个小时了
}
return ans;
}
struct Trie
{
Trie* next[MAX_D];
Trie* fail;
int no;
bool flag;
};
Trie tries[MAX_L * MAX_N];
int nP;
Trie* pRoot;
Trie* NewNode()
{
memset(&tries[nP], 0, sizeof(Trie));
tries[nP].no = nP;
return &tries[nP++];
}
void InitTrie(Trie*& pRoot)
{
nP = 0;
pRoot = NewNode();
}
void Insert(Trie* pRoot, char* pszPat)
{
Trie* pNode = pRoot;
while (*pszPat)
{
int idx = *pszPat - 'a';
if (pNode->next[idx] == NULL)
{
pNode->next[idx] = NewNode();
}
pNode = pNode->next[idx];
++pszPat;
}
pNode->flag = true;
}
void BuildAC(Trie* pRoot, Matrix& M)
{
pRoot->fail = NULL;
queue<Trie*> qt;
qt.push(pRoot);
M.Clear(nP);
while (!qt.empty())
{
Trie* front = qt.front();
qt.pop();
for ( int i = 0; i < MAX_D; ++i)
{
if (front->next[i])
{
Trie* pNode = front->fail;
while (pNode && pNode->next[i] == NULL)
{
pNode = pNode->fail;
}
front->next[i]->fail = pNode? pNode->next[i] : pRoot;
if (front->next[i]->fail->flag)
{
front->next[i]->flag = true;
}
qt.push(front->next[i]);
}
else
{
front->next[i] = front == pRoot? pRoot : front->fail->next[i];
}
// 这里必须要加上front->flag为false的判断么?加不加会生成不同的矩阵
if (!front->next[i]->flag)
{
++M.nD[front->no][front->next[i]->no];
}
}
}
}
int main()
{
int nN;
INT nL;
Matrix M(0);
while (scanf("%d%I64u", &nN, &nL) == 2)
{
InitTrie(pRoot);
while (nN--)
{
scanf("%s", szPat);
Insert(pRoot, szPat);
}
BuildAC(pRoot, M);
Matrix tmp(1);
tmp.nD[0][0] = 26;
tmp = SumPowMatrix(tmp, nL);
INT nAns = tmp.nD[0][0];
Matrix msum = SumPowMatrix(M, nL);
for ( int i = 0; i < msum.nSize; ++i)
{
nAns -= msum.nD[0][i];
}
printf("%I64u\n", nAns);
}
return 0;
}
#include < string.h>
#include <queue>
#include <algorithm>
using namespace std;
typedef unsigned long long INT;
const int MAX_D = 26;
const int MAX_L = 10;
const int MAX_N = 10;
char szPat[MAX_L];
const int MAX_S = 31;
struct Matrix
{
int nSize;
INT nD[MAX_S][MAX_S];
Matrix( int nS)
{
Clear(nS);
}
Matrix& operator = ( const Matrix& m)
{
nSize = m.nSize;
for ( int i = 0; i < nSize; ++i)
{
for ( int j = 0; j < nSize; ++j)
{
nD[i][j] = m.nD[i][j];
}
}
return * this;
}
void Clear( int nS)
{
nSize = nS;
memset(nD, 0, sizeof(nD));
}
void Unit()
{
for ( int i = 0; i < nSize; ++i)
{
for ( int j = 0; j < nSize; ++j)
{
nD[i][j] = (i == j ? 1 : 0);
}
}
}
};
Matrix operator+( const Matrix& A, const Matrix& B)
{
Matrix C(A.nSize);
for ( int i = 0; i < A.nSize; ++i)
{
for ( int j = 0; j < A.nSize; ++j)
{
C.nD[i][j] = A.nD[i][j] + B.nD[i][j];
}
}
return C;
}
Matrix operator*( const Matrix& nA, const Matrix& nB)
{
Matrix nC(nB.nSize);
for ( int i = 0; i < nA.nSize; ++i)
{
for ( int j = 0; j < nA.nSize; ++j)
{
for ( int k = 0; k < nA.nSize; ++k)
{
nC.nD[i][j] += nA.nD[i][k] * nB.nD[k][j];
}
}
}
return nC;
}
Matrix operator^(Matrix B, INT nExp)
{
Matrix ans(B.nSize);
ans.Unit();
while (nExp)
{
if (nExp % 2)
{
ans = ans * B;
}
B = B * B;
nExp >>= 1;
}
return ans;
}
// 求base^1+base^2++base^N
Matrix SumPowMatrix(Matrix& base, INT nN)
{
if (nN == 1)
{
return base;
}
Matrix ans = SumPowMatrix( base, nN / 2);
ans = ans + (( base^(nN / 2)) * ans); // 重载运算符保证不了优先级
if (nN % 2)
{
ans = ans + ( base^nN); // 没优先级啊,必须加括号,查错2个小时了
}
return ans;
}
struct Trie
{
Trie* next[MAX_D];
Trie* fail;
int no;
bool flag;
};
Trie tries[MAX_L * MAX_N];
int nP;
Trie* pRoot;
Trie* NewNode()
{
memset(&tries[nP], 0, sizeof(Trie));
tries[nP].no = nP;
return &tries[nP++];
}
void InitTrie(Trie*& pRoot)
{
nP = 0;
pRoot = NewNode();
}
void Insert(Trie* pRoot, char* pszPat)
{
Trie* pNode = pRoot;
while (*pszPat)
{
int idx = *pszPat - 'a';
if (pNode->next[idx] == NULL)
{
pNode->next[idx] = NewNode();
}
pNode = pNode->next[idx];
++pszPat;
}
pNode->flag = true;
}
void BuildAC(Trie* pRoot, Matrix& M)
{
pRoot->fail = NULL;
queue<Trie*> qt;
qt.push(pRoot);
M.Clear(nP);
while (!qt.empty())
{
Trie* front = qt.front();
qt.pop();
for ( int i = 0; i < MAX_D; ++i)
{
if (front->next[i])
{
Trie* pNode = front->fail;
while (pNode && pNode->next[i] == NULL)
{
pNode = pNode->fail;
}
front->next[i]->fail = pNode? pNode->next[i] : pRoot;
if (front->next[i]->fail->flag)
{
front->next[i]->flag = true;
}
qt.push(front->next[i]);
}
else
{
front->next[i] = front == pRoot? pRoot : front->fail->next[i];
}
// 这里必须要加上front->flag为false的判断么?加不加会生成不同的矩阵
if (!front->next[i]->flag)
{
++M.nD[front->no][front->next[i]->no];
}
}
}
}
int main()
{
int nN;
INT nL;
Matrix M(0);
while (scanf("%d%I64u", &nN, &nL) == 2)
{
InitTrie(pRoot);
while (nN--)
{
scanf("%s", szPat);
Insert(pRoot, szPat);
}
BuildAC(pRoot, M);
Matrix tmp(1);
tmp.nD[0][0] = 26;
tmp = SumPowMatrix(tmp, nL);
INT nAns = tmp.nD[0][0];
Matrix msum = SumPowMatrix(M, nL);
for ( int i = 0; i < msum.nSize; ++i)
{
nAns -= msum.nD[0][i];
}
printf("%I64u\n", nAns);
}
return 0;
}