背景:
要中考改卷,搬到了国际部的机房。
鼠标滚轮是坏的,差评。
一直不能上
luogu
\text{luogu}
luogu的原因是
DNS
\text{DNS}
DNS域名有问题。
题目传送门:
https://www.luogu.org/problemnew/show/P5337
题意:
给出
s
1
,
n
s1,n
s1,n,求长度为
n
n
n的字符串
s
2
s2
s2使得其相邻字母不与
s
1
s1
s1中的相邻字母重复(注意顺序)。
思路:
设
f
i
,
j
f_{i,j}
fi,j表示当前做到第
i
i
i位选字母
j
j
j的方案数。
显然有方程:
f
i
,
j
=
∑
k
f
i
−
1
,
k
[
k
,
j
不
相
邻
]
f_{i,j}=\sum_kf_{i-1,k}[k,j不相邻]
fi,j=∑kfi−1,k[k,j不相邻]。
显然时间复杂度为
Θ
(
2
6
2
n
)
\Theta(26^2n)
Θ(262n),显然行不通。
考虑
d
p
dp
dp的优化。
一种显然的思想是矩阵乘法。
考虑上面的性质,不妨搞一个
26
∗
26
26*26
26∗26的矩阵来表示是否可以从
k
k
k转移到
j
j
j(其实你的
30
p
t
s
30pts
30pts的做法也是如此)。
那就有:
[
b
a
s
e
]
∗
[
f
i
,
a
f
i
,
b
f
i
,
c
.
.
.
f
,
z
]
=
[
f
i
+
1
,
a
f
i
+
1
,
b
f
i
+
1
,
c
.
.
.
f
i
+
1
,
z
]
\left[ \begin{matrix} base \end{matrix} \right]*\left[ \begin{matrix} f_{i,a}\\ f_{i,b}\\ f_{i,c}\\ ...\\ f_{,z}\\ \end{matrix} \right]= \left[ \begin{matrix} f_{i+1,a}\\ f_{i+1,b}\\ f_{i+1,c}\\ ...\\ f_{i+1,z}\\ \end{matrix} \right]
[base]∗⎣⎢⎢⎢⎢⎡fi,afi,bfi,c...f,z⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡fi+1,afi+1,bfi+1,c...fi+1,z⎦⎥⎥⎥⎥⎤
其中
b
a
s
e
base
base就是是否可以转移的矩阵。
注意这里不像原来一样
f
f
f在前,转移矩阵在后,因为
f
i
+
1
,
a
f_{i+1,a}
fi+1,a从
f
i
,
a
,
f
i
,
b
,
f
i
.
c
,
.
.
.
,
f
i
,
z
f_{i,a},f_{i,b},f_{i.c},...,f_{i,z}
fi,a,fi,b,fi.c,...,fi,z转移到,符合矩阵乘法中的
(
i
,
j
)
=
(
i
,
k
)
∗
(
k
,
j
)
(i,j)=(i,k)*(k,j)
(i,j)=(i,k)∗(k,j)的思想。
注意
f
f
f的初始值是
1
1
1。
在代码中
f
=
o
p
f=op
f=op。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 1000000007
#define LL long long
using namespace std;
struct node
{
LL a[30][30];
void clear()
{
memset(a,0,sizeof(a));
}
friend node operator * (const node &a,const node &b)
{
node c;
c.clear();
for(int i=1;i<=26;i++)
for(int j=1;j<=26;j++)
for(int k=1;k<=26;k++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
return c;
}
} base,ans,op;
LL n;
int l;
char s[100010];
LL bz[30][30];
node work(LL x,node base)
{
node ans;
ans.clear();
for(int i=1;i<=26;i++)
ans.a[i][i]=1;
while(x)
{
if(x&1) ans=ans*base;
base=base*base;
x>>=1;
}
return ans;
}
int main()
{
scanf("%lld",&n);
scanf("%s",s+1);
l=strlen(s+1);
op.clear();
for(int i=1;i<=26;i++)
{
op.a[i][1]=1;
for(int j=1;j<=26;j++)
bz[i][j]=1;
}
for(int i=2;i<=l;i++)
bz[s[i-1]-'a'+1][s[i]-'a'+1]=0;
memcpy(base.a,bz,sizeof(base.a));
ans=work(n-1,base)*op;
LL sum=0;
for(int i=1;i<=26;i++)
sum=(sum+ans.a[i][1])%mod;
printf("%lld\n",sum);
}