您的位置:首页 > 其它

hdu 2243 考研路茫茫——单词情结

2011-05-06 22:01 357 查看
ac自动机 + 快速矩阵连成求和

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
////////////// ac自动机代码 //////////////
#define MAX_N 101
#define MAX_PAT 60
#define MAX_MAT 2000010
//子树个数
#define kind 26
struct Node
{
Node *fail;
Node *next[kind];
int count;
};
Node nodes[MAX_N];
int ncnt;
inline void iniTree() {ncnt = 0;}
inline Node* addNode() {
memset(&nodes[ncnt], 0, sizeof(Node));
return &nodes[ncnt++];
}
inline int getId(char ch) {
return ch - 'a';
}
void insert(char *str,Node *root)
{
Node *p=root;
int i=0,index;
while(str[i])
{
index = getId(str[i]);
if(p->next[index]==NULL)
p->next[index]=addNode();
p=p->next[index];
i++;
}
p->count++;
}
void build_ac_automation(Node *root, int chkind)
{
Node *r=root,*p;
queue<Node *>q;
root->fail=root;
root->count=0;
q.push(root);
while(!q.empty())
{
p=q.front();
q.pop();
p->count=p->count||p->fail->count; // ?????
for(int i=0;i<chkind;i++)
{
if(p->next[i]==NULL)//如果p->next[i]为空,则赋值为p的后缀的next[i]
{
if(p==root)
p->next[i]=root;
else
p->next[i]=p->fail->next[i];
}
else //如果p->next[i]不为空,则构造后缀(失败)节点
{
if(p==root)
p->next[i]->fail=root;
else
p->next[i]->fail=p->fail->next[i];
q.push(p->next[i]);
}
}
}
}
////////////// 下面是矩阵代码 //////////////
#define MSIZE 30
//#define mod 0xFFFFFFFFFFFFFFFFLL
struct mat{
ull a[MSIZE][MSIZE];
int top;
};

mat unit;
void init(int SIZE) //初始化单位矩阵,顺便把要初始化的全局矩阵m1等初始化。
{
int i,j;
unit.top=SIZE;
for(i=0;i<SIZE;i++)
{
for(j=0;j<SIZE;j++)
{
unit.a[i][j]=(i==j);
}
}
}
mat matadd(mat p,mat q)
{
int i,j;
for (i=0;i<p.top;i++)
{
for (j=0;j<p.top;j++)
{
p.a[i][j]+=q.a[i][j];
//p.a[i][j]%=mod;
}
}
return p;
}

mat matmul(mat p,mat q)
{
mat c;
int i,j,k;
c.top=p.top;
for (i=0;i<c.top;i++)
{
for (j=0;j<c.top;j++)
{
c.a[i][j] = 0;
for (k=0;k<c.top;k++)
{
c.a[i][j]+=(p.a[i][k]*q.a[k][j]);
//c.a[i][j]+=(p.a[i][k]*q.a[k][j])%mod;
//c.a[i][j]%=mod;
}
}
}
return c;
}

mat matmop(int t,mat m)
{
mat mm=unit;
if(t>0)
while(1)
{
if(t&1)
{
mm=matmul(mm,m);
}
t>>=1;
if(!t) break;
m=matmul(m,m);
}
return mm;
}
mat matsum(int k,mat mm3) //矩阵幂求和,signa(1~k) (mm3)^k
{
int n=0,s[65];//32位为int型,即log k
int i;
mat mm1,mm2;
while(k>0) {s[n++]=(k&1);k>>=1;}
mm2=mm1=mm3;
for(i=n-2;i>=0;i--)
{
mm1=matmul(mm1,matadd(mm2,unit));
mm2=matmul(mm2,mm2);
if(s[i])
{
mm2=matmul(mm2,mm3);
mm1=matadd(mm1,mm2);
}
}
return mm1;
}
////////////// 下面是问题代码 //////////////
char str[MAX_MAT];//主串
char pat[MAX_PAT];
int n,m, nodecnt;
mat matr;
Node *root;
void makeIniMar() {
for(int i = 0; i < nodecnt; ++i) {
if(nodes[i].count==0) {
for(int j = 0; j < kind; ++j) {
if(nodes[i].next[j] && nodes[i].next[j]->count==0) {
//printf("[%d %d]%d/n", i, j, nodes[i].next[j]-nodes);
matr.a[i][ nodes[i].next[j]-nodes ]++;
}
}
}
}
}
void show(mat ma) {
for(int i = 0; i < ma.top; ++i) {
for(int j = 0; j < ma.top; ++j) {
cout << ma.a[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
int main()
{
while(~scanf("%d%d", &n, &m)) {
iniTree();
root = addNode();
for(int i = 0; i < n; ++i) {
scanf("%s", &pat);
insert(pat, root);
}
build_ac_automation(root, kind);
nodecnt = ncnt;
init(nodecnt);
memset(&matr, 0, sizeof(matr));
matr.top = nodecnt;
makeIniMar();
//show(matr);
mat res = matsum(m, matr);
//show(res);
ull ans = 0;
for(int i = 0; i < nodecnt; ++i) {
ans += res.a[0][i];
}

init(1);
mat nimei;
nimei.top = 1;
nimei.a[0][0] = 26;
mat summat = matsum(m, nimei);
cout << summat.a[0][0] - ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: