yxy小蒟蒻的201125总结

2020.11.25 周三

我只能说

水逆

水逆

水逆

水逆

求转运

该挂分的都挂分了 不会的依旧纠结半天

稍微总结一下

A A A 就该挂分 没有初始化确实不是因为粗心 是我觉得不需要初始化

B B B 想了很多假算法 都把自己 h a c k hack hack 了 hd写的假 A C AC AC 的算法我考试的时候把它 h a c k hack hack 了 然而这个题完全脚造数据把这个假算法放过了?? 还绑了子任务的 所以 人 有时不要想得太多了 没话说呜

C C C 占坑有时间一定一定补 (真的好讨厌这种繁琐的题

D

角度的难题

题目背景

地狱中的判决,也是看钱说话的,正合我意。——角都

众所周知,角都能夺取忍者们尚在跳动的心脏保存在身上延长自身寿命,并通过其他忍者心脏上面的经 脉掌握新的查克拉属性。

角都作为晓的财政负责人,总是要帮组织接一些奇奇怪怪的任务,比如:“刺杀saber”,“从凹凸曼手中 拯救怪兽”,“帮大*丸偷N01P真题”,“三顾茅庐”,“帮某些盈利组织把试题再偷回来”。这些任务的难度为 S S E A S。

问题描述

最近他又接到了 n n n 个任务,难度分别为 s i s_i si 。这些任务难度按顺序读组成了字符串 S S S 。这个字符串看起来 很不美观,于是角都决定将这些任务五马分尸。即他要把这些任务分成五段,也就是找到五个字符串 A , B , C , D , E A,B,C,D,E A,B,C,D,E(可以是空串)使 A + B + C + D + E = S A+B+C+D+E=S A+B+C+D+E=S ,其中 + + + 表示把两个字符串首尾连接起来, 例如 “SS”+“E”+“AS”=“SSEAS”。

接下来角都会把 A + C + E A+C+E A+C+E 作为新的字符串 T T T ,他希望 T T T 是一个回文串,并且越长越好。由于角都算 不出最长能是多长,于是他也通灵了一名信息竞赛生过去帮他。

没错,那个倒霉蛋幸运儿还是你。 角度说:”我知道,大蛇丸的题已经把你弄自闭了,但是我不管,你就是得给我继续自闭。“(角都:可不 是我逼你的啊。)

把最两边组成的回文去掉就变成了上图的问题

一个区间从左边开始 一个在中间

先用马拉车算出每个中心点的回文半径

再用拓展 k m p kmp kmp 求出每个前缀 i i i 取反的字符串 和原串的 L C P LCP LCP (为了方便直接称它为 L C P LCP LCP

那么图中

情况一就直接求 R R R 右边的位置对应的 L C P LCP LCP 最长的就行了

讨论情况二

在求 L C P LCP LCP

s t r ( 1... a ) str(1...a) str(1...a) s t r ( i . . . j ) str(i...j) str(i...j) 两个拼起来可以组成回文

L C P j = j − i + 1 LCP_j=j-i+1 LCPj=ji+1

那么 定义 T O i = j TO_i=j TOi=j

情况二要求的就是 R R R R R R 左边的 T O TO TO 最大的值 那就是 R R R 科研延申的位置

(我但凡还记得马拉车和拓展 k m p kmp kmp 的话 也不至于想半天还不能 A A A

#include <bits/stdc++.h>
#define N 5000006
using namespace std;
char s[N],a[N],b[N];
int n,nn,ans,cnt,nxt[N<<1],ex[N],to[N],tmax[N],far[N],res;
void kmp(){
	nxt[1]=cnt;
	int l=0,r=0,j;
	for(int i=2;i<=cnt;i++){
		if(r>=i&&i+nxt[i-l+1]-1<r){
			nxt[i]=nxt[i-l+1]; continue;
		}
		if(r>=i) j=r+1-i+1; else j=1;
		while(a[j]==a[i+j-1]&&i+j-1<=cnt) j++;
		j--;
		nxt[i]=j; l=i; r=i+j-1;
	}
	l=r=0;
	for(int i=1;i<=cnt;i++){
		if(r>=i&&i+nxt[i-l+1]-1<r){
			ex[i]=nxt[i-l+1]; continue;
		}
		if(r>=i) j=r+1-i+1; else j=1;
		while(a[j]==b[i+j-1]&&i+j-1<=cnt) j++;
		j--;
		ex[i]=j; l=i; r=i+j-1;
	}
	far[cnt+1]=tmax[0]=0;
	for(int i=cnt;i>=1;i--){
		nxt[i]=ex[cnt-i+1];
		if(nxt[i])to[i-nxt[i]+1]=max(to[i-nxt[i]+1],i);
		far[i]=max(nxt[i],far[i+1]);
	}
	for(int i=1;i<=cnt;i++)
		tmax[i]=max(tmax[i-1],to[i]);
}
char c[N<<1]; //马拉车算法一定记得把空间扩大一倍
void malacher(){
	int l=0,r=0,j,pos;
	nn=cnt*2+1;
	c[1]='#';
	for(int i=1;i<=cnt;i++) c[i<<1]=a[i],c[i<<1|1]='#';
	for(int i=1;i<=nn;i++){
		pos=max(l+l-i,0);
		if(r>=i&&nxt[pos]+i-1<r){ nxt[i]=nxt[pos]; continue; }
		if(r>=i) j=r+1-i+1; else j=1;
		while(c[i-j+1]==c[i+j-1])j++;
		j--;
		nxt[i]=j; l=i; r=i+j-1;
	}
}
void solve(int l,int r){
	int ll=r-l+1;
	res=max(ll,res);
	if(r+l-1<=cnt)if(far[r+l-1]>=l-1)res=max(res,r+l-1);
	if(to[r+1]-r>l-1)res=max(res,r+l-1);
	else res=max(res,ll+((to[r+1]-r)<<1));
}
void work(){
	for(int i=1;i<=cnt;i++) 
		b[cnt-i+1]=a[i],
		to[i]=nxt[i]=ex[i]=tmax[i]=far[i]=0;
	kmp();
	malacher();
	int l,r;
	for(int i=2;i<nn;i++){
		r=(i+nxt[i]-2)>>1; l=(i-nxt[i]+2)>>1; if(l>r)continue;
		solve(l,r);
	}
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	int l=1,r=n;
	while(l<r&&s[l]==s[r])l++,r--,ans+=2;
	if(l>=r){ printf("%d\n",n); return 0; }
	for(int i=l;i<=r;i++) a[++cnt]=s[i];
	work();
	cnt=0;
	for(int i=r;i>=l;i--) a[++cnt]=s[i];
	work(); 
	cout<<ans+res;
}

纪念一下第一次写马拉车算法 (为啥放代码呢 因为我真的调了很久所以就想放上来呜呜呜

posted @ 2022-10-10 20:19  缙云山车神  阅读(26)  评论(0编辑  收藏  举报