CF506E Mr. Kitayuta's Gift 题解
Solution
挺有意思的。
我们考虑如何进行暴力 dp。可以看出我们可以设 \(f_{i,l,r}\) 表示还剩区间 \([l,r]\) 没有进行匹配,然后你构造的字符串已经考虑了前面 \(i\) 位和后面 \(i\) 位的方案数。转移式比较显然就不列了。
考虑优化的话可以发现我们可以矩阵加速,然后做到 \(m^6\log n\)。但是这显然是不能通过的。
考虑优化。考虑 \((l,r)\) 向转移点连边,可以发现对于一条链就对应一种转移,而链上真正关键的信息其实只有 \(s_l\not= s_r\) 的点有多少个,所以我们就可以把自动机点数优化到 \(\Theta(n)\)。
复杂度 \(\Theta(m^3\log n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 305
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
char ch[MAXN];
int n,m,f[MAXN][MAXN][MAXN],g[MAXN],g1[MAXN];//f[i][l][r]表示[l,r]经过i个s[l]!=s[r]的方案数
#define mod 10007
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
if (b < 0) b += (mod - 1);
int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
return res;
}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}
struct Matrix{
int mat[MAXN][MAXN];
Matrix(){memset (mat,0,sizeof (mat));}
int * operator [] (const int &key){return mat[key];}
Matrix operator * (const Matrix &p)const{
Matrix New;
for (Int i = 0;i <= 301;++ i)
for (Int j = i;j <= 301;++ j)
for (Int k = j;k <= 301;++ k) Add (New[i][k],mul (mat[i][j],p.mat[j][k]));
return New;
}
}A,B;
Matrix qkpow (Matrix a,int b){
Matrix res;
for (Int i = 0;i <= 301;++ i) res[i][i] = 1;
for (;b;b >>= 1,a = a * a) if (b & 1) res = res * a;
return res;
}
signed main(){
scanf ("%s",ch + 1),read (m),n = strlen (ch + 1);
f[0][1][n] = 1;
for (Int len = n;len >= 1;-- len)
for (Int l = 1;l + len - 1 <= n;++ l){
int r = l + len - 1;
for (Int i = 0;i <= n;++ i)
if (l == r || (r == l + 1 && ch[l] == ch[r])){
Add (g[i],f[i][l][r]);
if (l != r) Add (g1[i],f[i][l][r]);
}
else if (ch[l] == ch[r]) Add (f[i][l + 1][r - 1],f[i][l][r]);
else Add (f[i + 1][l + 1][r],f[i][l][r]),Add (f[i + 1][l][r - 1],f[i][l][r]);
}
for (Int i = 1;i <= n;++ i) B[i][i] = 24;
for (Int i = 0;i < n;++ i) B[i][i + 1] = 1;
int up = n + (n + 1) / 2 + 1;
for (Int i = n + 1;i < up;++ i) B[i][i] = 25;
for (Int i = n + 1;i < up;++ i) B[i][i + 1] = 1;
B[up][up] = 26;
for (Int i = 0;i <= n;++ i) if ((n - i + 1) / 2) B[i][up - (n - i + 1) / 2] = g[i];
A = qkpow (B,(n + m + 1) / 2 + 1);
int ans = A[0][up];
if (n + m + 1 & 1) write (ans),putchar ('\n');
else{
for (Int i = 0;i <= 301;++ i) for (Int j = 0;j <= 301;++ j) B[i][j] = 0;
for (Int i = 1;i <= n;++ i) B[i][i] = 24;
for (Int i = 0;i < n;++ i) B[i][i + 1] = 1;
for (Int i = n + 1;i < up;++ i) B[i][i] = 25;
for (Int i = n + 1;i < up;++ i) B[i][i + 1] = 1;
for (Int i = 0;i <= n;++ i) if ((n - i + 1) / 2) B[i][up - (n - i + 1) / 2] = g1[i];
A = qkpow (B,(n + m + 1) / 2 + 1),Sub (ans,A[0][up]);
write (ans),putchar ('\n');
}
return 0;
}