目录
显示
题目链接
https://www.luogu.org/problem/P5337
题解
先考虑常规的 DP。
设 \(f_{i,j}\) 代表当前为字符串第 \(i\) 位,且结尾为 \(j\) 的方案数,\(S_i\) 表示字符 \(i\) 前面能放的合法字符集,容易写出下面的状态转移方程:
$$f_{i,j}=\sum_{k \in S_j}{f_{i-1,k}}$$
显然这个可以通过矩阵乘法的形式进行优化。
这样我们就可以在 \(O(26^3 \log n)\) 的时间复杂度内解决本题了。
#include <iostream> #include <algorithm> #include <cstring> #define MOD 1000000007 using namespace std; struct mat { long long x[35][35]; mat() { memset(x,0,sizeof(x)); } }base; char s[100005]; mat operator*(mat a,mat b) { mat ans; for(int k=1;k<=26;k++) for(int i=1;i<=26;i++) for(int j=1;j<=26;j++) ans.x[i][j]=(ans.x[i][j]+a.x[i][k]*b.x[k][j])%MOD; return ans; } mat fpow(mat a,long long b) { mat ans; for(int i=1;i<=26;i++) ans.x[i][i]=1; while(b) { if(b&1)ans=ans*a; a=a*a; b>>=1; } return ans; } int main() { long long n,ans=0; cin>>n; cin>>s; int len=strlen(s); for(int i=1;i<=26;i++) for(int j=1;j<=26;j++) base.x[i][j]=1; for(int i=1;i<len;i++) base.x[s[i-1]-'a'+1][s[i]-'a'+1]=0; mat res=fpow(base,n-1); for(int i=1;i<=26;i++) for(int j=1;j<=26;j++) ans=(ans+res.x[i][j])%MOD; cout<<ans<<endl; return 0; }