修仙
Otomachi_Una_ · · 题解
题目简述
- 给定长度为
m 的字符串s ,你可以插入n 个小写字母,问最后可能得到多少个本质不同的回文串?
约定
- 定义
s 的生成串为在其中插入若干小写字母形成的字符串。 - 对于一条不一定简单的路径,去掉其中的自环组成新路径称之为「简化路径」。
解题思路
为了方便书写,我们下文中的
我们先考虑
首先
- 如果
l>r 我们称之为「目标点」,同样按照下面转移。 - 如果
l\leq r 且s_l=s_r 那么有25 的权值会传到自己,1 的权值传给f_{i+1,l+1,r-1} 。 - 如果
l\leq r 且s_l\not = s_r ,那么有24 的权值给自己,1 的权值传给f_{i+1,l+1,r} 和f_{i+1,l,r-1} 。
由于
我们继续观察上面的 dp 转移,不难发现它本质上是在走 DAG。如例子
其中点旁边的数字表示自环数,
我们需要从
一个简化路径加上自环所产生的权值应当只与其中
以此,我们只需要求出到达目标点
首先
然后
上图是一个
这样子复杂度是
但是利用矩阵乘法求出的是两两点之间长度一定的路径数量,不难可以把所有的路径合成一个更大的图,如下图所示:
实际上把所有边反过来更符合上面的图,不过代码使用的是这张图的建模。
当我们需要查询
这下可以做到
最终时间复杂度为
别忘了我们上面假设了
代码实现
不严谨的来说,直接暴力建是
还要注意的是
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MP make_pair
#define int youzi_xinzuo_jijiji
const int MAXN=205;
const int MOD=10007;
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int n,m,sz;
string s;
int rep_24[MAXN],rep_25[MAXN],rep_goal[MAXN];
int f[MAXN][MAXN][MAXN];// f[l,r,k] 从 [l,r] 到 goal 经过 k 个 24- 节点的方案数
struct matrix{
int a[MAXN<<1][MAXN<<1];
matrix(){memset(a,0,sizeof(a));}
friend matrix operator *(matrix x,matrix y){
matrix z;
for(int i=1;i<=sz;i++)
for(int k=i;k<=sz;k++) if(x.a[i][k])
for(int j=k;j<=sz;j++)
add(z.a[i][j],x.a[i][k]*y.a[k][j]%MOD);
return z;
}
}A,B;
matrix ksm(matrix a,int b){matrix res;for(int i=1;i<=sz;i++)res.a[i][i]=1;while(b){if(b&1)res=res*a;a=a*a,b>>=1;}return res;}
void build(){
for(int i=(n+1)/2;i>=1;i--){
rep_goal[i]=++sz;rep_25[i]=++sz;
if(i<(n+1)/2) A.a[rep_25[i+1]][rep_25[i]]=1;
A.a[rep_25[i]][rep_25[i]]=25;
A.a[rep_goal[i]][rep_25[i]]=1;
}
A.a[rep_25[1]][rep_goal[0]=++sz]=1;
for(int i=1;i<=n;i++){
rep_24[i]=++sz,
A.a[rep_24[i]][rep_24[i]]=24;
if(i>1) A.a[rep_24[i-1]][rep_24[i]]=1;
}
A.a[rep_25[1]][rep_24[1]]=1;
for(int i=0;i<=n;i++) A.a[rep_goal[i]][rep_goal[i]]=26;
B=ksm(A,(m+1)/2-1),A=B*A;
return;
}
int query(int x,int y){return A.a[rep_goal[x]][(y?rep_24[y]:rep_25[1])];}// x 25, y 24
int query1(int x,int y){return B.a[rep_25[x]][(y?rep_24[y]:rep_25[1])];}// x 25, y 24
int dfs(int l,int r,int k){
if(k<0) return 0;
if(f[l][r][k]>=0) return f[l][r][k];
if(l>r) return (k==0);
int ans=0;
if(s[l]==s[r]) ans=dfs(l+1,r-1,k);
else ans=(dfs(l+1,r,k-1)+dfs(l,r-1,k-1))%MOD;
return (f[l][r][k]=ans);
}
int main(){
ios::sync_with_stdio(false);
cin>>s>>m;n=s.length(),m+=n;
s=" "+s;
build();
memset(f,-1,sizeof(f));
ll ans=0;
for(int i=0;i<=n;i++){
ans+=dfs(1,n,i)*query((n-i+1)/2,i)%MOD;
if((m&1)&&(n-i)%2==0) ans-=dfs(1,n,i)*query1((n-i+1)/2,i)%MOD;
}
cout<<(ans%MOD+MOD)%MOD;
return 0;
}