题目大意
给定仅包含小写字母
a
∼
z
a \sim z
a∼z 的字符串
s
1
s_1
s1。你需要构造一个长度为
n
n
n 的字符串
s
2
s_2
s2,要求
s
1
s_1
s1 中的相邻的两个字母不能在
s
2
s_2
s2 中相邻地出现,求可行的方案数量对
1
0
9
+
7
10^9+7
109+7 取模后的值。
数据范围
1
⩽
n
⩽
1
0
15
,
1
⩽
∣
s
1
∣
⩽
1
0
5
1\leqslant n\leqslant 10^{15},1\leqslant |s_1|\leqslant 10^5
1⩽n⩽1015,1⩽∣s1∣⩽105
题解
定义矩阵
t
[
i
]
[
j
]
t[i][j]
t[i][j] 表示
i
i
i 字符右侧能否(1/0)为字符
j
j
j。
定义方程
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示以
j
j
j 字符结尾的长度位
i
i
i 的
s
2
s_2
s2 串的可行方案数量。
则有:
f
[
i
]
[
j
]
=
∑
k
=
1
26
f
[
i
−
1
]
[
k
]
(
t
[
k
]
[
j
]
=
=
1
)
f[i][j]=\sum\limits_{k=1}^{26}f[i-1][k](t[k][j]==1)
f[i][j]=k=1∑26f[i−1][k](t[k][j]==1)
时间复杂度为
Θ
(
2
6
2
n
)
\Theta(26^2n)
Θ(262n) ,铁定超时。
考虑优化转移,可以构造矩阵
a
a
a,满足
a
[
0
]
[
i
]
=
f
[
0
]
[
i
]
=
1
,
a
[
k
]
[
l
]
=
0
(
k
>
0
)
a[0][i]=f[0][i]=1,a[k][l]=0(k>0)
a[0][i]=f[0][i]=1,a[k][l]=0(k>0),则有:
a
×
t
=
[
f
[
i
]
[
0
]
0
0
…
0
f
[
i
]
[
1
]
0
0
…
0
f
[
i
]
[
2
]
0
0
…
0
…
…
…
…
0
f
[
i
]
[
26
]
0
0
…
0
]
×
t
=
[
f
[
i
+
1
]
[
0
]
0
0
…
0
f
[
i
+
1
]
[
1
]
0
0
…
0
f
[
i
+
1
]
[
2
]
0
0
…
0
…
…
…
…
0
f
[
i
+
1
]
[
26
]
0
0
…
0
]
\begin{aligned} a\times t&=\left[\begin{aligned} &f[i][0]&0&&0&&\dots&&0\\ &f[i][1]&0&&0&&\dots&&0\\ &f[i][2]&0&&0&&\dots&&0\\ &\dots&\dots&&\dots&&\dots&&0\\ &f[i][26]&0&&0&&\dots&&0\\ \end{aligned}\right]\times t\\ &=\left[\begin{aligned} &f[i+1][0]&0&&0&&\dots&&0\\ &f[i+1][1]&0&&0&&\dots&&0\\ &f[i+1][2]&0&&0&&\dots&&0\\ &\dots&\dots&&\dots&&\dots&&0\\ &f[i+1][26]&0&&0&&\dots&&0\\ \end{aligned}\right] \end{aligned}
a×t=⎣⎢⎢⎢⎢⎢⎢⎡f[i][0]f[i][1]f[i][2]…f[i][26]000…0000…0……………00000⎦⎥⎥⎥⎥⎥⎥⎤×t=⎣⎢⎢⎢⎢⎢⎢⎡f[i+1][0]f[i+1][1]f[i+1][2]…f[i+1][26]000…0000…0……………00000⎦⎥⎥⎥⎥⎥⎥⎤
因而考虑矩阵快速幂。时间复杂度为
Θ
(
2
6
2
log
2
n
)
\Theta(26^2\log_2n)
Θ(262log2n)。
#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
template<long long size>
struct arr{
long long a[size][size];
arr(){clear();}
arr(long long x[size][size]){
for(long long i=0;i<size;i++)
for(long long j=0;j<size;j++)
a[i][j]=x[i][j];
}
void clear(){memset(a,0,sizeof a);}
long long *operator[](long long x){return a[x];}
friend void print(const arr &x){
for(long long i=0;i<size;i++,printf("\n"))
for(long long j=0;j<size;j++)
printf("%d ",x.a[i][j]);
}
friend arr operator*(const arr &x,const arr &y){
arr c;
for(long long i=0;i<size;i++)
for(long long j=0;j<size;j++)
for(long long k=0;k<size;k++)
c[i][j]=(c[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
return c;
}
friend arr pow(const arr &x,long long k){
if(k==1) return x;
arr t=pow(x,k>>1);
if((k&1)==1) return t*t*x;
return t*t;
}
};
arr<26> t,a;
long long n;
long long len;
char str[2000010];
int main(void)
{
scanf("%lld",&n);
if(n==1){
printf("26\n");
return 0;
}
scanf("%s",str);len=strlen(str);
for(long long i=0;i<26;i++)
for(long long j=0;j<26;j++)
t[i][j]=1;
for(long long i=0;i<26;i++)
a[i][0]=1;
for(long long i=1;i<len;i++)
t[str[i]-'a'][str[i-1]-'a']=0;
long long ans=0;
arr<26> tans=pow(t,n-1)*a;
for(long long i=0;i<26;i++)
ans=(ans+tans[i][0]%mod)%mod;
printf("%lld",ans%mod);
return 0;
}