BZOJ1009 單模板自動機 矩陣快速冪優化DP
阿新 • • 發佈:2019-01-09
第一次在BZOJ自己做出不是那麼水的題,但是看這過題人數。。。嘛還是寫一下題解吧
題目大意:求只由0到9組成的不包含m(m<=20)位模式串的n(n<=1e9)位字串的個數
涉及到字串匹配的話 很自然應該往KMP和自動機的方向想。
然後可以很容易發現建自動機可以得到一個DP做法:
定義
那麼對每個
都有
那麼答案就是
然後n很大 那麼就矩陣快速冪吧
至此問題完美解決!
程式碼:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iomanip>
#include<vector>
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i,k,n) for(int i=(k);i<=(n);i++)
#define rep0(i,n) for(int i=0;i<(n);i++)
#define red(i,k,n) for(int i=(k);i>=(n);i--)
#define sqr(x) ((x)*(x))
#define clr(x,y) memset((x),(y),sizeof(x))
#define pb push_back
const int maxn=100;
const int maxs=10;
int n,m,mod;
int nxt[maxn][maxs],fail[maxn];
int root,tot;
int newnode()
{
for(int i=0;i<maxs;i++)nxt[tot][i]=-1;
return tot++;
}
void init()
{
tot=0;
root=newnode();
}
void insert(char str[])
{
int len=strlen(str);
int now=root;
for(int i=0;i<len;i++)
{
char s=str[i]-'0';
if(nxt[now][s]==-1)
nxt[now][s]=newnode();
now=nxt[now][s];
}
}
void build()
{
queue<int> q;
fail[root]=root;
for(int i=0;i<maxs;i++)
{
if(nxt[root][i]==-1)
nxt[root][i]=root;
else
{
fail[nxt[root][i]]=root;
q.push(nxt[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<maxs;i++)
{
if(nxt[now][i]==-1)
nxt[now][i]=nxt[fail[now]][i];
else
{
fail[nxt[now][i]]=nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
}
}
struct MAT
{
int a[25][25];
int n;
void init(int x,int m)
{
clr(a,0);
n=m;
if(x)rep0(i,n)a[i][i]=1;
}
MAT operator * (const MAT &x) const
{
MAT ret;ret.init(0,n);
rep0(i,n)rep0(j,n)rep0(k,n)(ret.a[i][j]+=a[i][k]*x.a[k][j]%mod)%=mod;
return ret;
}
void add(int x,int y)
{
a[x][y]++;
}
};
MAT quipow(MAT x,LL k)
{
MAT ret;ret.init(1,x.n);
while(k)
{
if(k&1)ret=ret*x;
x=x*x;
k>>=1;
}
return ret;
}
char str[30];
int main()
{
scanf("%d%d%d",&n,&m,&mod);
scanf("%s",str);
init();
insert(str);
build();
MAT A;A.init(0,m);
rep0(i,m)
{
rep0(j,10)
{
if(nxt[i][j]!=m)
{
A.add(nxt[i][j],i);
}
}
}
MAT B=quipow(A,n);
int ans=0;
rep0(i,m)ans+=B.a[i][0];
printf("%d\n",ans%mod);
return 0;
}