• 【codeforces



    description

    给定字符串 (s),需要在 (s) 中添加 (n) 个字符(可以添在开头或末尾)使得 (s) 变回文。

    求最后可以得到本质不同的回文串。

    problem link。


    solution

    定义 (f_{l,r,k}) 表示回文串的最前/最后 (k) 个字符匹配上 (s)(1dots l-1)(r+1dots|s|) 的方案数。
    转移讨论 (s_l = s_r) 是否成立即可。最后依回文串长度的奇偶性分类讨论。

    很明显可以矩乘,但是状态数达到 (O(|s|^2)),显然过不了。

    那么出题人的意思就是让我们压缩状态。但是我们懒得找性质,所以直接用 BM 硬刚即可。

    求出前 (A = 1000) 项的全局答案(不知道准确上界,不过1000项应该够了),然后 BM + 多项式取模可以做到 (O(|s|^2A + A^2log n))。下面的代码附的就是这个做法。

    附一个BM算法流程的博客。关于为什么构造出来的一定最短,可以尝试阅读 mx 的集训队论文(由于我水平有限,没有读懂,所以就不附证明了)


    考虑合理合法地压缩状态。冷静分析一下,我们可以把状态和转移建图:

    picture

    一条路径的方案数事实上只与这个路径上的红点个数有关(绿点个数可以根据红点个数算出来)。

    那么先 dp 一遍求出有多少路径包含 (i) 个红点,再用这 (O(s)) 状态新建一个转移图:

    最后时间复杂度 (O(s^3log n)),听说有些卡常,需要利用三角矩阵的特性把矩阵乘法的部分优化一下。

    由于我懒癌,所以就不写这种做法了。


    code

    #include <map>
    #include <cstdio>
    #include <cstring>
    #include <cassert>
    #include <algorithm>
    using namespace std;
    
    #define rep(i, x, n) for(int i=x;i<=n;i++)
    #define per(i, x, n) for(int i=x;i>=n;i--)
    
    const int MOD = 10007;
    const int M = 1000;
    const int N = 2*M;
    
    inline int add(int x, int y) {x += y; return x >= MOD ? x - MOD : x;}
    inline int sub(int x, int y) {x -= y; return x < 0 ? x + MOD : x;}
    inline int mul(int x, int y) {return (int) (1LL * x * y % MOD);}
    int mpow(int b, int p) {
    	int r; for(r=1;p;p>>=1,b=mul(b,b))
    		if( p & 1 ) r = mul(r, b);
    	return r;
    }
    
    namespace linear_seq{
    
    int t1[N + 5], t2[N + 5];
    void pmul_mod(int *A, int *B, int *C, int *M, int n) {
    	rep(i, 0, n - 1) t1[i] = A[i], t2[i] = B[i];
    	per(i, 2*(n - 1), 0) C[i] = 0;
    	rep(i, 0, n - 1) if( t1[i] )
    		rep(j, 0, n - 1) C[i + j] = add(C[i + j], mul(t1[i], t2[j]));
    	per(i, 2*(n - 1), n) if( C[i] )
    		per(j, n, 0) C[i - j] = sub(C[i - j], mul(C[i], M[n - j]));
    }
    
    int b[N + 5], md[N + 5], bk;
    
    void debug(int *A, int n) {
    	rep(i, 1, bk) printf("%d%c", b[i], (i == bk) ? '
    ' : ' ');
    	rep(i, bk + 1, n) {
    		int d = A[i];
    		rep(j, 1, bk) d = sub(d, mul(b[j], A[i - j]));
    		assert(d == 0);
    	}
    }
    
    int r[N + 5], c[N + 5], ck, rk, iv, nw;
    void update(int x, int d) {
    	if( nw == -1 || ck - x < rk - nw ) {
    		rk = ck, nw = x, iv = mpow(d, MOD - 2);
    		rep(i, 1, rk) r[i] = c[i];
    	}
    }
    
    int f[N + 5], g[N + 5];
    int get(int *A, int n, int m) {
    //	if( m <= n ) return A[m];
    	
    	rk = bk = 0, nw = -1;
    	rep(i, 1, n) {
    		int d = A[i];
    		rep(j, 1, bk) d = sub(d, mul(b[j], A[i - j]));
    		if( d ) {
    			rep(j, 1, bk) c[j] = b[j]; ck = bk;
    			if( nw == -1 ) {
    				bk = i; rep(j, 1, bk) b[j] = 0; 
    			} else {
    				int t = i - nw + rk;
    				rep(j, bk + 1, t) b[j] = 0;
    				bk = max(bk, t);
    				
    				int coef = mul(d, iv), p = i - nw;
    				b[p] = add(b[p], coef);
    				rep(j, 1, rk) b[p + j] = sub(b[p + j], mul(coef, r[j]));
    			}
    			update(i, d);
    		}
    	}
    	
    //	debug(A, n);
    	
    	rep(i, 1, bk) md[bk - i] = sub(0, b[i]); md[bk] = 1;
    	f[1] = 1, g[0] = 1;
    	for(;m;m>>=1,pmul_mod(f, f, f, md, bk))
    		if( m & 1 ) pmul_mod(g, f, g, md, bk);
    	
    	int ret = 0;
    	rep(i, 0, bk - 1) ret = add(ret, mul(g[i], A[i + 1]));
    	return ret;
    }
    
    }
    
    int f[2][M + 5][M + 5], a[M + 5];
    char s[M + 5]; int n, len;
    int main() {
    	scanf("%s%d", s + 1, &n), len = strlen(s + 1), n += len;
    	
    	int res = 0; f[0][1][len] = 1;
    	rep(i, 1, M) {
    		rep(j, 1, len) rep(k, j, len)
    			f[1][j][k] = f[0][j][k], f[0][j][k] = 0;
    		res = mul(res, 26);
    		rep(j, 1, len) {
    			res = add(res, f[1][j][j]);
    			f[0][j][j] = add(f[0][j][j], mul(f[1][j][j], 25));
    			rep(k, j + 1, len) {
    				if( s[j] == s[k] ) {
    					f[0][j][k] = add(f[0][j][k], mul(25, f[1][j][k]));
    					if( j + 1 == k ) res = add(res, f[1][j][k]);
    					else f[0][j + 1][k - 1] = add(f[0][j + 1][k - 1], f[1][j][k]);
    				} else {
    					f[0][j][k] = add(f[0][j][k], mul(24, f[1][j][k]));
    					f[0][j + 1][k] = add(f[0][j + 1][k], f[1][j][k]);
    					f[0][j][k - 1] = add(f[0][j][k - 1], f[1][j][k]);
    				}
    			}
    		}
    		
    		if( n & 1 ) {
    			a[i] = mul(res, 26);
    			rep(p, 1, len) a[i] = add(a[i], f[0][p][p]);
    		} else a[i] = res;
    	}
    	
    	printf("%d
    ", linear_seq::get(a, M, n / 2 - 1));
    }
    

    details

    突然感觉到了BM是多么好用的一个东西。

  • 相关阅读:
    leetcode 字符串的全排列 All In One
    数据结构栈 All In One
    vscode code snippets not working All In One
    js 使用 canvas 实现一个一笔一画写汉字的效果 All In One
    社保 & 养老金 & 养老保险 All In One
    python 中 lambda 函数
    linux 中vim 中的回退、前进
    python 中统计fasta文件scaffolds平均长度、最长scaffolds、最短scaffolds
    ubuntu 中设置 root登录filezilla
    python中统计基因组所含N碱基总个数
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/13332909.html
Copyright © 2020-2023  润新知