P13790 「CZOI-R6」Border
P13790 「CZOI-R6」Border
upd:2026.8.20 修正代码一处错误
思路
暴力就是枚举 \(border\) 的长度然后在其中暴力判断,时间复杂度 \(O(n^2)\)。而我们发现,由于它每次只会改变一个字符,所以对于前缀和后缀来说,总共也就只能容忍之多两个不同的位置。所以我们可以枚举答案并二分出这两个不同的位置(或一个),然后判断一下能否只修改一个字符实现。
代码实现
主要的问题在于如何二分,我们可以同时而这两个位置,第一部分 dfs 是只有一对的字符串不一致,选择字符串不一致的那边。如果两边字符串都不一致,那么就进入第二部分的普通二分,单独二分刚才求出的两对不一致字符串不一致的位置,如果在第二部分发现还是有两个不一致的字符串对,那么直接返回特殊值表示错误。判断字符串是否一致只需要用用哈希优化达就可以做到到 \(O(n\log n)\) 的时间复杂度。注意:如果搜到了大于两个位置要设成以便判断。
正确代码
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long double ld;
#define freop(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define endl '\n'
#define inf 0x7f7f7f7f
#define lb(x) ((x)&-(x))
#define pii pair<int,int>
#define fir first
#define sec second
#define mkp(a,b) make_pair(a,b)
const int N=1e6+1;
const ull hh=2791;
int n,fi,se;
ull pw[N]={1},h[N];
string s;
inline void H(){for(int i = 1;i<=n;++i) h[i]=h[i-1]*hh+s[i];}
//处理哈希数组
inline ull sub(int l,int r){return h[r]-h[l-1]*pw[r-l+1];}
//截取其中一段的哈希值
inline int js(int l1,int r1,int l2,int r2){//第二部分的二分
int lm,rm;
bool f1,f2;
while(r1^l1){
lm=l1+r1>>1,rm=l2+r2>>1,
f1=sub(l1,lm)^sub(l2,rm),//左半边的字符串是否一致
f2=sub(lm+1,r1)^sub(rm+1,r2);//右半边
if(f2&&f1) return -1;//有两个以上的错误
if(f1) r1=lm,r2=rm;
else l1=lm+1,l2=rm+1;
}
return l1;
}
void dfs(int l1,int r1,int l2,int r2){//第一部分dfs
if(l1==r1){fi=l1;return ;}//如果只有一处不同
int lm=l1+r1>>1,rm=l2+r2>>1;
bool f1=sub(l1,lm)^sub(l2,rm);//同上的js()中的变量
bool f2=sub(lm+1,r1)^sub(rm+1,r2);
if(f1&&f2)//两边都不一致,前往第二阶段
fi=js(l1,lm,l2,rm),
se=js(lm+1,r1,rm+1,r2);
else
if(f1) dfs(l1,lm,l2,rm);
else dfs(lm+1,r1,rm+1,r2);
}
inline bool ck(int len){
fi=se=0,dfs(1,len,n-len+1,n);
if(!~fi||!~se) return 0;//特殊值表示无解
if(!se){
if(fi<=n-len||n-len+fi>len) return 1;
else return (s[fi-(n-len)]==s[n-len+fi]);
//只有一个不同的位置,看是否可以不修改在交汇处,或是交汇处相同
}
return (len-fi==n-se);//有两个不同的位置
}
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
cout.tie(0);
for(int i = 1;i^N;++i) pw[i]=pw[i-1]*hh;//哈希预处理
// freop();
//↑以上为初始化↑
//------------------------------
cin >> s,n=s.size(),s=" "+s,H();
for(int i = n-1;i;--i)//枚举border
if(ck(i)){cout << i << endl;return 0;}
cout << 0 << endl;
return 0;
}

浙公网安备 33010602011771号