zoukankan      html  css  js  c++  java
  • [CF932G]Palindrome Partition(PAM回文划分dp)

    题面

    https://codeforces.com/problemset/problem/932/G

    题解

    前置知识

    在做此题之前,需要了解利用PAM在(O(n log n))时间内解决最小回文划分、回文划分数等回文划分相关dp的方法(见上面链接)

    有了这个基础,我们再做此题。由于"第一个与最后一个相同,第二个与倒数第二个相同……"这样的条件极难dp,所以我们考虑转化题意。

    如何做呢?首先如果给出的字符串长度为奇数,那肯定是0啦。

    否则的话,将字符串的前后半部分拆开,将后半部分翻转,再把它们“拉链式”合并。以本题样例1为例:

    就成功地将原题那个恶心的条件变成了求回文串划分方案数。样例1的答案ab|cd|cd|ab对应着新序列的abba|cddc。

    另外有一个地方与之前的回文划分dp不同,就是这里的回文划分中的每一个回文串长度必须是偶数。不过这个也好解决,dp时将所有奇数位的dp值都设成0就可以了。

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    #define rg register
    #define In inline
    
    const int N = 1e6;
    const ll mod = 1e9 + 7;
    
    namespace ModCalc{
    	In void Inc(ll &x,ll y){
    		x += y;if(x >= mod)x -= mod;
    	}
    	In void Dec(ll &x,ll y){
    		x -= y;if(x < 0)x += mod;
    	}
    	In ll Add(ll x,ll y){
    		Inc(x,y);return x;
    	}
    	In ll Sub(ll x,ll y){
    		Dec(x,y);return x;
    	}
    }
    using namespace ModCalc;
    
    char t[N+5],s[N+5];
    int n;
    ll f[N+5],g[N+5],slink[N+5],diff[N+5];
    
    struct PAM{
    	ll nx[N+5][26],len[N+5],fail[N+5];
    	int last,cnt;
    	void clear(){
    		cnt++;
    		len[1] = -1;
    		fail[0] = fail[1] = 1;
    	}
    	void extend(char c,int n){
    		int id = c - 'a';
    		int p = last;
    		while(s[n-len[p]-1] != s[n])p = fail[p];
    		if(!nx[p][id]){
    			cnt++;
    		 	len[cnt] = len[p] + 2;
    		 	int q = fail[p];
    		 	while(s[n-len[q]-1] != s[n])q = fail[q];
    		 	fail[cnt] = nx[q][id];
    		 	nx[p][id] = cnt;
    		 	diff[cnt] = len[cnt] - len[fail[cnt]];
    		 	if(diff[cnt] != diff[fail[cnt]])
    		 		slink[cnt] = fail[cnt];
    	 		else
    		 		slink[cnt] = slink[fail[cnt]];
    		} 
    		last = nx[p][id];
    		p = last;
    		while(p >= 2){
    			g[p] = f[n-len[slink[p]]-diff[p]];
    			if(diff[p] == diff[fail[p]])Inc(g[p],g[fail[p]]);
    			if(!(n & 1))Inc(f[n],g[p]);
    			p = slink[p];
    		}
    	}	
    }P;
    
    int main(){
    	scanf("%s",t + 1);
    	n = strlen(t + 1);
    	if(n & 1){
    		puts("0");return 0;
    	}
    	P.clear();
    	ll _n = 0;
    	for(rg int i = 1;(i << 1) <= n;i++)s[++_n] = t[i],s[++_n] = t[n+1-i];
    	f[0] = 1;
    	for(rg int i = 1;i <= n;i++)P.extend(s[i],i);
    	cout<<f[n]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    1648 最大和
    poj2243
    Codevs 2307[SDOI2009]HH的项链
    2597 团伙
    一个JavaWeb项目中使用的部分技术
    Oracle 11g 学习3——表空间操作
    iOS实现抽屉效果
    用shell脚本实现linux系统上wifi模式(STA和soft AP)的转换
    Codeforces Round #243 (Div. 1)——Sereja and Two Sequences
    站点选择配色诀窍
  • 原文地址:https://www.cnblogs.com/xh092113/p/12398609.html
Copyright © 2011-2022 走看看