Live2D

CF506E Mr. Kitayuta's Gift 题解

link

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;
}
posted @ 2022-02-24 17:41  Dark_Romance  阅读(34)  评论(0编辑  收藏  举报