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

8 篇文章 0 订阅
2 篇文章 0 订阅

本题解很易懂!

原题地址

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

n ≤ 1 e 15 n \le 1e15 n1e15

不难想到一个很暴力的 d p dp dp
d p [ i ] [ j ] dp[i][j] dp[i][j]为长度为 i i i且当前字符为 j j j的合法字符串个数 ( m o d 1 e 9 + 7 ) (mod 1e9+7) (mod1e9+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 dp[i][j]=k=126dp[i1][k](k,j)s
∀ 1 ≤ i ≤ 26 d p [ 1 ] [ i ] = 1 \forall_{1\le i \le 26}dp[1][i]=1 1i26dp[1][i]=1
a n s = ∑ i = 1 26 d p [ n ] [ i ] ans=\sum_{i=1}^{26}dp[n][i] ans=i=126dp[n][i]
时间复杂度 O ( 2 6 2 n ) O(26^2n) O(262n)?反正T飞。
我们珂以把上面的式子变一下,设 w [ i ] [ j ] = [ ( i , j ) ∉ s ] w[i][j]=[(i,j)\not\in s] w[i][j]=[(i,j)s],即若 ( i , j ) (i,j) (i,j) s s s中不连续,则 w [ i ] [ j ] = 1 w[i][j]=1 w[i][j]=1,否则 w [ i ] [ j ] = 0 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] dp[i][j]=k=126dp[i1][k]×w[k][j]
珂能你一开始没看懂, d p [ i − 1 ] [ k ] × w [ k ] [ j ] dp[i-1][k] \times w[k][j] dp[i1][k]×w[k][j]是啥呢?
分析一下,若 ( k , j ) ∉ s (k,j)\not \in s (k,j)s,那么 w [ k ] [ j ] = 1 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] dp[i1][k]×w[k][j]=dp[i1][k],贡献为 d p [ i − 1 ] [ k ] dp[i-1][k] dp[i1][k],符合题意。
( i , j ) ∈ s (i,j)\in s (i,j)s,则 w [ k ] [ j ] = 0 w[k][j]=0 w[k][j]=0,贡献为 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) c[i][j]=a[i][k]×b[k][j](kp)
我们建 n n n 1 × 26 1\times 26 1×26的矩阵 F 1 , F 2 , F 3 , ⋯ F n F_1,F_2,F_3,\cdots F_n F1,F2,F3,Fn,分别代表 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] dp[1][126],dp[2][126],dp[3][126]dp[n][126]再建一个 26 ∗ 26 26*26 2626的矩阵 A 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) F1=[11111]261

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] A=w[1][1]w[2][1]w[26][1]w[1][2]w[2][2]w[26][2]w[1][3]w[2][3]w[26][3]w[1][26]w[2][26]w[26][26]

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

? ? ? \color{red}???

什么操作?
如果您的矩阵基础扎实,请跳过此步骤。
C = F 1 × A n − 1 C=F_1\times A^{n-1} C=F1×An1,则
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) C(1,1)=F1(1,1)×An1(1,1)+F1(1,2)×An1(2,1)++F1(1,26)×An1(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) F1=[11111]261
所以
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(1,1)=An1(1,1)+An1(2,1)++An1(26,1)
其他点以此类推
发现 C C C矩阵的所有数的和就是 A n − 1 A^{n-1} An1矩阵的所有数的和。
这其实是矩阵的简单的游戏。
时间复杂度 O ( 2 6 3 l o g n ) O(26^3logn) O(263logn),能过。
C o d e \color{blue}Code 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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值