显而易见有一个记录末尾字母的 (O(n)) 递推。
显而易见可以用矩阵快速幂优化,不妨用一个 (1 imes 26) 的矩阵维护当前 DP 值,初始化为:
[egin{bmatrix}
1&1&1cdots 1&1&1
end{bmatrix}]
构造一个 (26 imes 26) 的转移矩阵,如果 (i) 不能转移到 (j) 那么 ((j,i)=0) 否则 ((j,i)=1),这个根据矩阵乘法定义来。
然后就做完了,记得开 long long
,时间复杂度 (O(log n))。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 26
#define Mod 1000000007
#define For(i,x,y)for(i=x;i<=(y);i++)
ll n;
string s1;
namespace Subtask1
{
bool bo[N][N];
int f[2][100005];
void init()
{
int i,j,k;
For(i,0,s1.size()-2)bo[s1[i]-'a'][s1[i+1]-'a']=1;
For(i,0,25)f[1][i]=1;
For(i,2,n)
{
For(j,0,25)
For(k,0,25)
if(!bo[j][k])f[i&1][k]=(f[i&1][k]+f[i&1^1][j])%Mod;
For(j,0,25)f[i&1^1][j]=0;
}
For(k,1,25)f[n&1][0]=(f[n&1][0]+f[n&1][k])%Mod;
cout<<f[n&1][0];
}
}
namespace Subtask2
{
struct matrix
{
int g[N][N];
}a,b,c;
matrix mul(matrix p,matrix q)
{
int i,j,k;
For(i,0,25)
For(j,0,25)
{
c.g[i][j]=0;
For(k,0,25)c.g[i][j]=(c.g[i][j]+1LL*p.g[i][k]*q.g[k][j])%Mod;
}
return c;
}
void init()
{
int ans=0,i,j;
For(i,0,25)
{
For(j,0,25)b.g[i][j]=1;
a.g[0][i]=1;
}
For(i,0,s1.size()-2)b.g[s1[i]-'a'][s1[i+1]-'a']=0;
n--;
while(n)
{
if(n&1)a=mul(a,b);
b=mul(b,b);
n>>=1;
}
For(i,0,25)ans=(ans+a.g[0][i])%Mod;
cout<<ans;
}
}
int main()
{
// freopen("str.in","r",stdin);
// freopen("str.out","w",stdout);
int i;
cin>>n>>s1;
if(n>100000)Subtask2::init();
else Subtask1::init();
return 0;
}