栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【CF906E】 Reverses(动态规划,回文自动机)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【CF906E】 Reverses(动态规划,回文自动机)

题面

 

给你两个长度为 n n n 的小写字母字符串 s s s 和 t t t。你可以翻转 t t t 的若干个不相交的区间,要求最终 s s s 和 t t t 相同。问你最少翻转几个区间,并输出方案。

1 ≤ ∣ S ∣ = ∣ T ∣ ≤ 500000 1leq|S|=|T|leq 500000 1≤∣S∣=∣T∣≤500000 。

题解

我们把两个串合并为一个新串 A A A ,满足 A 2 i = S i , A 2 i + 1 = T i A_{2i}=S_i,A_{2i+1}=T_i A2i​=Si​,A2i+1​=Ti​ ( i ∈ { 0 , 1 , . . . , ∣ S ∣ − 1 } iin{0,1,...,|S|-1} i∈{0,1,...,∣S∣−1}),答案就是把 A A A 分割成若干偶数长度回文串,长度 > 2 >2 >2 的回文串最小个数。

可以很容易地想出朴素DP,
d p [ i ] = min ⁡ A [ j . . . i ] 回 文 { d p [ j − 1 ] + [ i > j + 1 ] } dp[i]=min_{A[j...i]回文}{dp[j-1]+[i>j+1]} dp[i]=A[j...i]回文min​{dp[j−1]+[i>j+1]}

枚举回文串的过程可以用回文自动机快速完成。

但这个还是 O ( n 2 ) O(n^2) O(n2) 的,于是我们想利用回文串的性质优化:

如果 fail 和原长度相差过小,意味着后面有一段等差数列,我们用前缀和优化,可以一次性考虑一整个等差数列。对于每个回文串,fail 的等差数列只有 O ( log ⁡ ) O(log ) O(log) 个。

前缀和优化的方法有很多种,这里就不详细展开了。时间复杂度 O ( n log ⁡ n ) O(nlog n) O(nlogn)

CODE

这里提供了一种巧妙的实现方式

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 1000005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define PR pair
int xchar() {
	static const int maxn = 1000000;
	static char b[maxn];
	static int pos = 0,len = 0;
	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
	if(pos == len) return -1;
	return b[pos ++];
}
// #define getchar() xchar()
LL read() {
	LL f = 1,x = 0;int s = getchar();
	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
	return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x<0) putchar('-'),x = -x;
	return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

const int MOD = 100000267;
int n,m,s,o,k;
char a[MAXN],b[MAXN];
int ss[MAXN];
struct PAM{
	int s[26],len,fail;
	PAM(){memset(s,0,sizeof(s));len=fail=0;}
	PAM(int l,int f) {memset(s,0,sizeof(s));len=l;fail=f;}
}pam[MAXN] = {PAM(0,1),PAM(-1,1)};
int lx[MAXN];
int las = 0,cnt = 1,Len = 0;
int getfail(int x) {
	while(ss[Len-pam[x].len-1] != ss[Len]) x = pam[x].fail;
	return x;
}
int addpam(int c) {
	Len ++;
	int p = getfail(las);
	int np = pam[p].s[c];
	if(!np) {
		np = ++ cnt; pam[np] = PAM();
		pam[np].len = pam[p].len + 2;
		pam[np].fail = pam[getfail(pam[p].fail)].s[c];
		int bf = pam[np].fail,bbf = pam[bf].fail;
		if(pam[np].len + pam[bbf].len == pam[bf].len*2) lx[np] = lx[bf];
		else lx[np] = bf;
		pam[p].s[c] = np;
	}
	las = np;
	return np;
}
struct it{
	int nm,pr;
	it(){nm=0x3f3f3f3f;pr=0;}
	it(int N,int P){nm=N;pr=P;}
}dp[MAXN],sum[MAXN];
inline bool operator < (it a,it b) {return a.nm < b.nm;}
inline bool operator > (it a,it b) {return b < a;}
int fnp[MAXN];
void Print(int x,int cn) {
	if(!x) return AIput(cn,'n');
	int p = fnp[x];
	if(dp[p].nm == dp[x].nm) return Print(p,cn);
	return Print(p,cn+1),AIput((p>>1)+1,' '),AIput(x>>1,'n');
}
int main() {
	scanf("%s",a + 1);
	scanf("%s",b + 1);
	n = strlen(a + 1);
	for(int i = 1;i <= n;i ++) {
		ss[++ m] = a[i]-'a';
		ss[++ m] = b[i]-'a';
	}
	dp[0] = it(0,0);
	ss[0] = -1;
	for(int i = 1;i <= (n<<1);i ++) {
		dp[i] = it();
		addpam(ss[i]);
		int p = las;
		while(p > 1) {
			int lp = pam[p].len,bf = pam[p].fail;
			int l2 = pam[bf].len,l3 = pam[lx[p]].len;
			if(bf == lx[p]) sum[p] = dp[i-lp];
			else sum[p] = min(sum[bf],dp[i-(l3+lp-l2)]);
			dp[i] = min(dp[i],it(sum[p].nm+1,sum[p].pr));
			p = lx[p];
		}
		if(ss[i] == ss[i-1]) dp[i] = min(dp[i],dp[i-2]);
		fnp[i] = dp[i].pr; dp[i].pr = i;
		if(i&1) dp[i] = it();
	}
	if(dp[n<<1].nm > n) return AIput(-1,'n'),0;
	Print(n<<1,0);
	return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883093.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号