P9613 解题报告
Hoks
·
·
题解
前言
比较简单的 ACAM+矩阵优化 dp。
广告:串串博客。
类似题目:
P3502 [POI2010] CHO-Hamsters。
SP1676 GEN - Text Generator。
CF696D Legen...。
P3715 [BJOI2017] 魔法咒语。
最后一题是这题的严格加强版(指加强到你被迫打个暴力)。
(这四个人认为难度单增,这题貌似可以放在最前面?)
思路分析
这个题就很小清新了,因为笔者写过这题的严格加强版。
发现是给定的 q 个串不能出现即为多模匹配,考虑对于这 q 个字符串建出 ACAM,给末尾打上标记,再在 fail 树建出来的时候传一下标记。
然后考虑怎么计算方案数。
由于是计数问题,且 q 不大,直接考虑跑暴力 dp。
套路地设计 dp_{i,j} 表示填了 i 位,在 ACAM 上跑到状态 j 时的方案数。
转移的时候考虑大力,尝试每个字符往下转移。
假设最后返回的状态为 x,那么转移方程式即为:
dp_{i+1,x}=dp_{i,j}
转移的时候记得累加一下和就行了。
最后的答案就是 \sum\limits^{tot}_{i=1}dp_{l,n}。
理由也很简单,最后可能停留在 ACAM 上的任意一个点上。
接着考虑怎么优化,套路的想到把 ACAM 上的一个状态看做一个点,把走 $1$ 步的方案数的邻接矩阵 $base$ 处理出来后 $base^l$ 表示走 $l$ 步的方案数。
那这样的话最后的答案就 $\sum\limits^{tot}_{i=1}res_{0,i},res=base^l$。
构造矩阵时直接每个节点尝试往下匹配就行了,然后判断一下这两个状态是不是都可以走即可。
## 代码
```cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=210,INF=0x3f3f3f3f3f3f3f3f,mod=1e9+7;
int n,m,l,le,ans,mx,len[N],dp[N][N];char s[N][N],t[N];
struct ACAM
{
struct node{int nxt,ed,v[26];}t[N];int tot=0;
inline void insert(char s[],int n)
{
int u=0;
for(int i=1;i<=n;i++){if(!t[u].v[s[i]-'a']) t[u].v[s[i]-'a']=++tot;u=t[u].v[s[i]-'a'];}
t[u].ed=1;
}
inline void build()
{
queue<int>q;
for(int i=0;i<26;i++) if(t[0].v[i]) t[t[0].v[i]].nxt=0,q.push(t[0].v[i]);
while(!q.empty())
{
int u=q.front();q.pop();t[u].ed|=t[t[u].nxt].ed;
for(int i=0;i<26;i++)
if(t[u].v[i]) t[t[u].v[i]].nxt=t[t[u].nxt].v[i],q.push(t[u].v[i]);
else t[u].v[i]=t[t[u].nxt].v[i];
}
}
}ac;
struct Matrix
{
int a[N][N];
Matrix(){memset(a,0,sizeof a);}
};
namespace Fast_IO
{
static char buf[1000000],*paa=buf,*pd=buf;
#define getchar() paa==pd&&(pd=(paa=buf)+fread(buf,1,1000000,stdin),paa==pd)?EOF:*paa++
inline int read()
{
int x(0),t(1);char fc(getchar());
while(!isdigit(fc)&&fc!=-1){if(fc=='-') t=-1;fc=getchar();}
while(isdigit(fc)&&fc!=-1) x=(x<<1)+(x<<3)+(fc^48),fc=getchar();
if(fc==-1) exit(0);return x*t;
}
inline void print(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline bool chk(char c) { return !(c>='a'&&c<='z'); }
inline bool ck(char c) { return c!='\n'&&c!='\r'&&c!=-1; }
inline void rd(char s[],int&n)
{
s[++n]=getchar();
while(chk(s[n])) s[n]=getchar();
while(ck(s[n])) s[++n]=getchar();
n--;
}
}
using namespace Fast_IO;
Matrix mul(Matrix x,Matrix y)
{
Matrix res;
for(int i=0;i<=mx;i++)
for(int j=0;j<=mx;j++)
for(int k=0;k<=mx;k++)
{
res.a[i][j]+=x.a[i][k]*y.a[k][j];
res.a[i][j]=res.a[i][j]>=mod?res.a[i][j]%mod:res.a[i][j];
}
return res;
}
inline Matrix ksm(Matrix x,int y)
{
Matrix res;for(int i=0;i<=mx;i++) res.a[i][i]=1;
while(y)
{
if(y&1) res=mul(res,x);
x=mul(x,x);y>>=1;
}
return res;
}
signed main()
{
l=read(),m=read();
for(int i=1;i<=m;i++) read(),le=0,rd(t,le),ac.insert(t,le);
ac.build();Matrix base;mx=ac.tot;
for(int x=0;x<=ac.tot;x++)
for(int i=0;i<26;i++)
{
int v=ac.t[x].v[i];
if(!ac.t[x].ed&&!ac.t[v].ed) base.a[x][v]++;
}
Matrix tt=ksm(base,l),t;t.a[0][0]=1;t=mul(t,tt);
for(int pos=0;pos<=ac.tot;pos++) ans=(ans+t.a[0][pos])%mod;
print(ans);
return 0;
}
```