题目地址:http://poj.org/problem?id=2778
数据很大,二维数组开不下,所以第一次写用了滚动数组,但是TLE
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<vector>
using namespace std;
typedef long long LL;
const int letter=4;
const int INF=0x3f3f3f3f;
struct Node{
Node *pChilds[letter],*pPrev;
bool bBadNode;
Node(){
memset(pChilds,0,sizeof(pChilds));
pPrev=NULL; bBadNode=false;
}
}tree[100+5];
char patten[20+5];
LL d[2][100+5];
int nNode;
map<char,int> idx;
//d[i][j]要长度为i到达节点j,也即是tree[j] 字符串个数
void Insert(Node* root,char* s)
{
for(int i=0;s[i];i++)
{
if(root->pChilds[idx[s[i]]]==NULL)
root->pChilds[idx[s[i]]]=tree+nNode++;
root=root->pChilds[idx[s[i]]];
}
root->bBadNode=true;
}
void BuildDfa()
{
for(int i=0;i<letter;i++)
tree[0].pChilds[i]=tree+1;
tree[1].pPrev=tree;
tree[0].pPrev=NULL;
queue<Node*> Q;
Q.push(tree+1);
while(!Q.empty())
{
Node* root=Q.front(); Q.pop();
for(int i=0;i<letter;i++)
{
Node* p=root->pChilds[i];
if(p==NULL) continue;
Node* pPrev=root->pPrev;
while(pPrev!=NULL){
if(pPrev->pChilds[i]!=NULL){
p->pPrev=pPrev->pChilds[i];
if(p->pPrev->bBadNode) p->bBadNode=true;
break;
}
else pPrev=pPrev->pPrev;
}
Q.push(p);
}
}
}
int main()
{
idx['A']=0;idx['T']=1,idx['G']=2,idx['C']=3;
int N,M; cin>>M>>N; nNode=2;
for(int i=0;i<M;i++){
scanf("%s",patten);
Insert(tree+1,patten);
}
BuildDfa();
d[0][1]=1;
for(int i=0;i<N;i++)
{
memset(d[i%2^1],0,sizeof(d[0]));
for(int j=1;j<nNode;j++)
{
if(tree[j].bBadNode) continue;
for(int k=0;k<letter;k++)
{
Node* pPrev=tree+j;
while(pPrev){
if(pPrev->pChilds[k]!=NULL){
if(pPrev->pChilds[k]->bBadNode) break;
int son=pPrev->pChilds[k]-tree;
d[i%2^1][son]+=d[i%2][j];
if(d[i%2^1][son]>100000) d[i%2^1][son]-=100000;
break;
}
pPrev=pPrev->pPrev;
}
}
}
}
LL ans=0;
for(int i=1;i<nNode;i++) {
ans+=d[N%2][i];
if(ans>100000) ans-=100000;
}
cout<<ans;
return 0;
}
下面用矩阵优化
d[i][j]表示i节点到j节点的个数
也即是 d[i][j]=∑ d[i][k]+d[n][k]
这和矩阵的运算法则一样
所以直接矩阵快速幂n次就好了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<vector>
using namespace std;
typedef long long LL;
const int letter=4;
const int INF=0x3f3f3f3f;
struct Matrix{
LL a[100+5][100+5];
int r; // r*r
Matrix(int r=100+5):r(r){memset(a,0,sizeof(a));} //初始化长
void MakeI(int x){ //变为x*E的单位矩阵
memset(a,0,sizeof(a));
for(int i=0;i<r;i++) a[i][i]=x;
}
Matrix operator * (const Matrix& m) { //矩阵乘法
Matrix result(r);
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
{
for(int k=0;k<r;k++)
result.a[i][j]+=a[i][k]*m.a[k][j];
}
return result;
}
Matrix operator % (const int p){ //矩阵对每个元素取余
Matrix result(*this);
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
result.a[i][j]%=p;
return result;
}
Matrix operator + (const Matrix& m){ //矩阵互相相加
Matrix result(r);
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
result.a[i][j]=a[i][j]+m.a[i][j];
return result;
}
Matrix operator + (int n){ //加上个常数
Matrix result(r);
result.MakeI(n);
return *this+result;
}
};
Matrix PowMod(const Matrix& m,int k,int p) //矩阵快速幂
{ //m^k mod p
int r=m.r;
Matrix result(r);
result.MakeI(1); //变成单位矩阵
Matrix base=m;
while(k){
if(k&1) result=result*base%p;
base=base*base%p;
k>>=1;
}
return result;
}
struct Node{
Node *pChilds[letter],*pPrev;
bool bBadNode;
Node(){
memset(pChilds,0,sizeof(pChilds));
pPrev=NULL; bBadNode=false;
}
}tree[100+5];
char patten[20+5];
int nNode;
map<char,int> idx;
//d[i][j] 指节点i到j的步数 i,j都是安全节点,且其中也不经过危险节点
void Insert(Node* root,char* s)
{
for(int i=0;s[i];i++)
{
if(root->pChilds[idx[s[i]]]==NULL)
root->pChilds[idx[s[i]]]=tree+nNode++;
root=root->pChilds[idx[s[i]]];
}
root->bBadNode=true;
}
void BuildDfa()
{
for(int i=0;i<letter;i++)
tree[0].pChilds[i]=tree+1;
tree[1].pPrev=tree;
tree[0].pPrev=NULL;
queue<Node*> Q;
Q.push(tree+1);
while(!Q.empty())
{
Node* root=Q.front(); Q.pop();
for(int i=0;i<letter;i++)
{
Node* p=root->pChilds[i];
if(p==NULL) continue;
Node* pPrev=root->pPrev;
while(pPrev!=NULL){
if(pPrev->pChilds[i]!=NULL){
p->pPrev=pPrev->pChilds[i];
if(p->pPrev->bBadNode) p->bBadNode=true;
break;
}
else pPrev=pPrev->pPrev;
}
Q.push(p);
}
}
}
int main()
{
idx['A']=0;idx['T']=1,idx['G']=2,idx['C']=3;
int N,M; cin>>M>>N; nNode=2;
for(int i=0;i<M;i++){
scanf("%s",patten);
Insert(tree+1,patten);
}
BuildDfa();
Matrix d(nNode);
for(int i=1;i<nNode;i++)
{
if(tree[i].bBadNode) continue;
for(int j=0;j<letter;j++)
{
Node* pPrev=tree+i;
while(pPrev){
if(pPrev->pChilds[j]!=NULL){
if(pPrev->pChilds[j]->bBadNode) break;
int son=pPrev->pChilds[j]-tree;
d.a[i][son]++;
if(d.a[i][son]>=100000) d.a[i][son]-=100000;
break;
}
pPrev=pPrev->pPrev;
}
}
}
Matrix m=PowMod(d,N,100000);
LL ans=0;
for(int i=1;i<nNode;i++)
if(!tree[i].bBadNode) {
ans+=m.a[1][i];
if(ans>=100000) ans-=100000;
}
cout<<ans;
return 0;
}