洛谷 P5337 [TJOI2019]甲苯先生的字符串 题解

本题解很易懂!

原题地址

给你一个数 n n 和一个字符串 s s ,求符合长度为 n n 且在 s s 中连续的字符不能连续出现,即这个字符串中不能出现 s s 的连续子串,答案对 1 e 9 + 7 1e9+7 取模。

n 1 e 15 n \le 1e15

不难想到一个很暴力的 d p dp
d p [ i ] [ j ] dp[i][j] 为长度为 i i 且当前字符为 j j 的合法字符串个数 ( m o d 1 e 9 + 7 ) (mod 1e9+7) ,不难推式子:
d p [ i ] [ j ] = k = 1 26 d p [ i 1 ] [ k ] ( k , j ) ∉ s dp[i][j]=\sum_{k=1}^{26}dp[i-1][k]|(k,j)\not\in s
1 i 26 d p [ 1 ] [ i ] = 1 \forall_{1\le i \le 26}dp[1][i]=1
a n s = i = 1 26 d p [ n ] [ i ] ans=\sum_{i=1}^{26}dp[n][i]
时间复杂度 O ( 2 6 2 n ) O(26^2n) ?反正T飞。
我们珂以把上面的式子变一下,设 w [ i ] [ j ] = [ ( i , j ) ∉ s ] w[i][j]=[(i,j)\not\in s] ,即若 ( i , j ) (i,j) s s 中不连续,则 w [ i ] [ j ] = 1 w[i][j]=1 ,否则 w [ i ] [ j ] = 0 w[i][j]=0
式子变成了:
d p [ i ] [ j ] = k = 1 26 d p [ i 1 ] [ k ] × w [ k ] [ j ] dp[i][j]=\sum_{k=1}^{26}dp[i-1][k]\times w[k][j]
珂能你一开始没看懂, d p [ i 1 ] [ k ] × w [ k ] [ j ] dp[i-1][k] \times w[k][j] 是啥呢?
分析一下,若 ( k , j ) ∉ s (k,j)\not \in s ,那么 w [ k ] [ j ] = 1 w[k][j]=1 d p [ i 1 ] [ k ] × w [ k ] [ j ] = d p [ i 1 ] [ k ] dp[i-1][k]\times w[k][j]=dp[i-1][k] ,贡献为 d p [ i 1 ] [ k ] dp[i-1][k] ,符合题意。
( i , j ) s (i,j)\in s ,则 w [ k ] [ j ] = 0 w[k][j]=0 ,贡献为 0 0
你可能会说“时间复杂度并没有变…”
确实没有变,但是这个式子珂以优化了。
感觉这个式子像什么?对!矩阵乘法!!!
矩乘的板子是 c [ i ] [ j ] = a [ i ] [ k ] × b [ k ] [ j ] ( k p ) c[i][j]=a[i][k]\times b[k][j](k\le p)
我们建 n n 1 × 26 1\times 26 的矩阵 F 1 , F 2 , F 3 , F n F_1,F_2,F_3,\cdots F_n ,分别代表 d p [ 1 ] [ 1 26 ] , d p [ 2 ] [ 1 26 ] , d p [ 3 ] [ 1 26 ] d p [ n ] [ 1 26 ] dp[1][1\cdots26],dp[2][1\cdots26],dp[3][1\cdots26]\cdots dp[n][1\cdots26] 再建一个 26 26 26*26 的矩阵 A A 具体含义见下面。
初始化:
F 1 = [ 1 1 1 1 1 ] 26 1 F_1= \left[ \begin{matrix} 1 &1 &1 &1\cdots 1 \end{matrix} \right] (26个1)

A = [ w [ 1 ] [ 1 ] w [ 1 ] [ 2 ] w [ 1 ] [ 3 ] w [ 1 ] [ 26 ] w [ 2 ] [ 1 ] w [ 2 ] [ 2 ] w [ 2 ] [ 3 ] w [ 2 ] [ 26 ] w [ 26 ] [ 1 ] w [ 26 ] [ 2 ] w [ 26 ] [ 3 ] w [ 26 ] [ 26 ] ] A= \left[ \begin{matrix} w[1][1]&w[1][2]&w[1][3]&\cdots &w[1][26] \\ w[2][1]&w[2][2]&w[2][3] &\cdots&w[2][26] \\ \vdots &\vdots &\vdots &\ddots&\vdots \\ w[26][1]&w[26][2]&w[26][3]&\cdots &w[26][26] \end{matrix} \right]

不难推出 F i = F i 1 × A ( i > 1 ) F_i=F_{i-1}\times A(i>1)
然而模拟矩阵乘也会炸啊…
矩阵乘法是 O ( 2 6 3 ) O(26^3) 的时间复杂度,算上递推的 O ( n ) O(n) 就是 O ( n × 2 6 3 ) O(n\times 26^3) ,惊,被暴力吊打!
然而还有一个神器,矩阵快速幂
(不会快速幂的珂以退出补知识了)
我们知道矩乘是有分配律的,但是这个顺推的式子好像不像是矩阵快速幂的样子…
那么开始下面一波操作:
F 2 = F 1 × A F_2=F_1\times A
F 3 = F 2 × A F_3=F_2\times A
然后我们将上面求的 F 2 F_2 代入:
F 3 = F 1 × A × A = F 1 × A 2 F_3=F_1\times A\times A=F_1\times A^2
F 4 = F 3 × A = F 1 × A 3 F_4=F_3\times A=F_1\times A^3
\vdots
F n = F 1 × A n 1 F_n=F_1\times A^{n-1}
妙啊!
a n s = i = 1 26 F n ( 1 , i ) ans=\sum_{i=1}^{26}F_n(1,i)
但是你会发现,如果只到这一步的话,最后还要算一个 F 1 × A n 1 F_1 \times A^{n-1} ,爆掉。
但其实,
i = 1 26 F n ( 1 , i ) = i = 1 26 j = 1 26 A n 1 ( i , j ) \sum_{i=1}^{26}F_n(1,i)=\sum_{i=1}^{26}\sum_{j=1}^{26} A^{n-1}(i,j)

\color{red}???

什么操作?
如果您的矩阵基础扎实,请跳过此步骤。
C = F 1 × A n 1 C=F_1\times A^{n-1} ,则
C ( 1 , 1 ) = F 1 ( 1 , 1 ) × A n 1 ( 1 , 1 ) + F 1 ( 1 , 2 ) × A n 1 ( 2 , 1 ) + + F 1 ( 1 , 26 ) × A n 1 ( 26 , 1 ) C(1,1)=F_1(1,1)\times A^{n-1}(1,1)+F_1(1,2)\times A^{n-1}(2,1) +\cdots +F_1(1,26)\times A^{n-1}(26,1)
因为
F 1 = [ 1 1 1 1 1 ] 26 1 F_1= \left[ \begin{matrix} 1 &1 &1 &1\cdots 1 \end{matrix} \right] (26个1)
所以
C ( 1 , 1 ) = A n 1 ( 1 , 1 ) + A n 1 ( 2 , 1 ) + + A n 1 ( 26 , 1 ) C(1,1)=A^{n-1}(1,1)+A^{n-1}(2,1)+\cdots+ A^{n-1}(26,1)
其他点以此类推
发现 C C 矩阵的所有数的和就是 A n 1 A^{n-1} 矩阵的所有数的和。
这其实是矩阵的简单的游戏。
时间复杂度 O ( 2 6 3 l o g n ) O(26^3logn) ,能过。
C o d e \color{blue}Code

# include <bits/stdc++.h>
using namespace std;
struct Martix
{
	long long a[30][30];
}A;
unsigned long long n;
char s[100010];
const long long mod=1e9+7;
Martix operator *(const Martix &x,const Martix &y) 
{
	Martix ans;
	for(int i=1;i<=26;i++) for(int j=1;j<=26;j++) ans.a[i][j]=0;
	for(int i=1;i<=26;i++) 
	{
		for(int j=1;j<=26;j++) 
		{
			for(int k=1;k<=26;k++) 
			{
			ans.a[i][j]=(ans.a[i][j]+(x.a[i][k]%mod)*(y.a[k][j]%mod)%mod)%mod;
			ans.a[i][j]%=mod;
			}
		}
	}
	return ans;
}
Martix js(Martix x,long long n) 
{
	Martix ans;
	for(int i=1;i<=26;i++)
	{
		for(int j=1;j<=26;j++) 
		{
			ans.a[i][j]=0;
		}
	}
	for(int i=1;i<=26;i++) ans.a[i][i]=1;
	while(n) 
	{
		if(n&1) 
		{
			ans=ans*x;
			n--;
		}
		x=x*x;
		n>>=1;
	}
	return ans;
}
int main(void) 
{
	scanf("%llu%s",&n,&s);
	for(int i=1;i<=26;i++) 
	{
		for(int j=1;j<=26;j++) 
		{
			A.a[i][j]=1;
		}
	}
	for(int i=1;i<strlen(s);i++) 
	{
		A.a[s[i-1]-'a'+1][s[i]-'a'+1]=0;
	}
	Martix ans=js(A,n-1) ;
	long long tot=0;
	for(int i=1;i<=26;i++) 
	{
		for(int j=1;j<=26;j++) 
		{
		//	cout<<ans.a[i][j]<<" ";
			tot=(tot%mod)+(ans.a[i][j]%mod)%mod;
		}
		//cout<<endl;
	}
	cout<<tot%mod<<endl; 
	return 0;
}
发布了24 篇原创文章 · 获赞 32 · 访问量 3788

猜你喜欢

转载自blog.csdn.net/woshidalaocxy/article/details/104909551