首先不难列出一个
O(n⋅262)
O
(
n
⋅
26
2
)
的DP方程:
设
fi,c
f
i
,
c
表示权值最多为
i
i
,结尾字符为的方案数,
vx,y
v
x
,
y
为
x,y
x
,
y
的差异值,那么有
注意到 vx,y≤5 v x , y ≤ 5 ,那么如果把 i i 相同的状态看成一行,把每行合成一块,那么某一块的状态要么从上一块转移过来,要么从当前块转移过来,这样就可以矩阵快速幂优化了。
具体的,假设 fy→fx f y → f x ( y y 和是两维状态压成一维),若 fy f y 在上一块就直接在系数 Ax,y A x , y 上 +1 + 1 ,若在当前块就把 Ay,... A y , . . . 加到 Ax,... A x , . . . 即可。
复杂度 O((5⋅26)3logn) O ( ( 5 ⋅ 26 ) 3 log n ) 。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define up(x,y) (x=(x+(y))%mod)
#define ll long long
#define G(x,y) ((x)*26+(y))
using namespace std;
const int mod=1000000007;
int n,m,v[30][30];
struct matrix
{
int h,w;
ll a[135][135];
matrix(int xh,int xw)
{
h=xh,w=xw;
for(int i=0;i<h;i++)
for(int j=0;j<w;j++)
a[i][j]=0;
}
matrix operator *(matrix &b)
{
matrix re(h,b.w);
for(int i=0;i<h;i++)
for(int j=0;j<b.w;j++)
for(int k=0;k<w;k++)
up(re.a[i][j],a[i][k]*b.a[k][j]);
return re;
}
}f(131,1),g(131,131);
matrix ksm(matrix t,ll b)
{
matrix re(t.h,t.w);
for(int i=0;i<t.h;i++)
re.a[i][i]=1;
for(;b;b>>=1)
{
if(b&1) re=re*t;
t=t*t;
}
return re;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<26;i++)
for(int j=0;j<26;j++)
v[i][j]=1;
for(int i=1;i<=m;i++)
{
char x,y;int z;
scanf("%s%s%d",&x,&y,&z);
v[x-'a'][y-'a']=v[y-'a'][x-'a']=z;
}
for(int i=0;i<=130;i++)
f.a[i][0]=g.a[i][130]=1;
for(int i=0;i<=4;i++)
for(int c=0;c<26;c++)
{
for(int d=0;d<26;d++)
if(i-v[c][d]<0) up(g.a[G(i,c)][G(i-v[c][d]+5,d)],1);
else
{
for(int j=0;j<=130;j++)
up(g.a[G(i,c)][j],g.a[G(i-v[c][d],d)][j]);
up(f.a[G(i,c)][0],f.a[G(i-v[c][d],d)][0]);
}
}
f=ksm(g,n/5)*f;
ll ans=0;
for(int c=0;c<26;c++)
up(ans,f.a[G(n%5,c)][0]);
printf("%lld",ans);
return 0;
}