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=j−i+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;
}
纪念一下第一次写马拉车算法 (为啥放代码呢 因为我真的调了很久所以就想放上来呜呜呜