您的位置:首页 > 其它

[Codeforces Round #286 DIV1E (CF506E)] Mr. Kitayuta's Gift

2017-01-24 12:05 501 查看

题意

字符集大小26,给出一个串s(n=|s|≤200),现任意插入正好m个字符,询问构成回文串的个数,答案取模。

题解

按照题解。

1. dp(l,r,i)代表回文串的左i位可以匹配s的第l位,回文串的右i位可以匹配s的第r位。下面假设n+m为偶数

2. 将状态转移图画出来如图一(以串abaac为例),图中将存在24自环的点标为红色(Red),存在25自环的点标为绿色(Green)。设右上角的表示dp(1,n,0)的状态为START,从START走长度为n+m2的路径到达GOAL的方案数即为答案。



3. 可以发现这是一个DAG,故将所有的START→GOAL的链找出来,如图二。



4. 此时已经不关心原来字符串的数据了。又可以发现每一条链上,红点和绿点的顺序对答案没有影响,所以把红点放在前面,按红点数量排个序,再合并一下,如图三。



5. 显然,对于每一条链,红点数量为i,那么绿点数量为⌈n−i2⌉,这决定了最多有n条不同的链,每条链有倍数,下面用(R,G)来表示一条链,其中R是红点个数,G是绿点个数。

6. 每条(R,G)链可以拆分成(R+1,G),(R+1,G−1)两条链,如图四,第一个绿点将一条边指向了另一个绿点,这个新绿点跟原链的绿点环境相同,但是原来的绿点少了一条边变成了红点。



7. 将所有的(R,G)进行这种拆分,将其画在坐标图中,如图五,形成了点(⌈n2⌉,0),(⌈n2⌉+1,0),⋯,(n−1,0),(n,0),(n,1),⋯,(n,⌈n2⌉)并且能相应求出每种链有几条。



8. 把最终形成的链合并起来,如图六,这就是n+m为偶数的情形,用矩阵快速幂求解。



9. 那么n+m为奇数,呢?先求出来长度为n+m+12的答案,然后减去不合法的串,什么样的串不合法呢?所有在图1中走到表示状态dp(i,i+1)的点是不合法的。那么把这些点当做终点再进行一遍相同的dp,然后进行相同的步骤拆分链,合并链,构建自动机,矩阵快速幂。

代码

/// by ztx
#include <cstdio>
#include <cstring>

#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define  mod  10007LL
#define  N 208LL
#define  M N*3/2

char s
;
int f[N][N][N] = {0};
inline void dp(int n,int del=0) {
int l, r, k;
if (del) memset(f,0,sizeof f);
Rev (l,n,1) Rep (r,l,n) {
if (del) {
if (l == r) continue;
if (r == l+1) { f[l][r][0] = (s[l]==s[r]?1:0); continue; }
} else if (l == r) { f[l][r][0] = 1; continue; }
if (s[l] == s[r]) {
if (l+1 <= r-1) Rep (k,0,n) f[l][r][k] = f[l+1][r-1][k];
if (r == l+1) f[l][r][0] = 1;
} else {
f[l][r][0] = 0;
Rep (k,1,n) f[l][r][k] = (f[l+1][r][k-1]+f[l][r-1][k-1]) % mod;
}
}
}

inline int pow(int x,int p) {
if (p <= 0) return 1; int ret = 1;
for (; p; p>>=1, (x*=x)%=mod) if (p&1) (ret*=x)%=mod;
return ret;
}

int n, T[M][M], A[M][M];

int io, jo;
inline void ZERO(int A[M][M]) { Rep(io,1,n) Rep (jo,1,n) A[io][jo] = 0; }
inline void ONE(int A[M][M]) { Rep(io,1,n) A[io][io] = 1; }

int ic, jc;
inline void COPY(int to[M][M],int from[M][M]) { Rep (ic,1,n) Rep (jc,ic,n) to[ic][jc] = from[ic][jc]; }

int C[M][M], im, jm, km;
inline void MUL(int A[M][M],int B[M][M]) {
ZERO(C);
Rep (im,1,n) Rep (jm,im,n) Rep (km,im,jm) (C[im][jm] += A[im][km]*B[km][jm]%mod) %= mod;
COPY(A,C);
}

int X[M][M];
inline void POW(int A[M][M],int p) {
COPY(X,A);
for (ZERO(A), ONE(A); p; p>>=1, MUL(X,X)) if (p&1) MUL(A,X);
}

int g[N][N] ;
inline int solve(int *f,int n,int len,int del=0) {
if (del) memset(g,0,sizeof g);
int i, j, h = (n+1)/2, GOAL = n+h+1;
Rep (i,0,n) g[i][(n-i+1)/2] = f[i];
rep (i,0,n) Rep (j,1,h) {
(g[i+1][j] += g[i][j]) %= mod;
(g[i+1][j-1] += g[i][j]) %= mod;
g[i][j] = 0;
}
::n = n+h+1;
ZERO(T), ZERO(A), A[1][1] = 1;
rep (i,1,n+h) T[i][i+1] = 1;
Rep (i,1,n+h) T[i][i] = (i<=n ? 24 : 25);
Rep (i,h,n+h) T[i][GOAL] = (i<=n ? g[i][0] : g
[i-n]);
T[GOAL][GOAL] = (del ? 25 : 26);
POW(T,len), MUL(A,T);
return A[1][GOAL];
}

int main() {
int n, m, ans, len;
scanf("%s%d", s+1, &m), n = strlen(s+1);
dp(n);
len = (n+m+1)/2;
ans = solve(f[1]
,n,len);
if ((n+m)%2 == 0 || n == 1) {}
else if (n == 2) {
if (s[1] == s[2]) ans = (ans-pow(25,len-1)+mod)%mod;
} else {
dp(n,1);
ans = (ans-solve(f[1]
,n-2,len-1,1)+mod)%mod;
}
printf("%d\n", ans);
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: