Strings in the Pocket(题目链接)
题意:
输入2个串s1、s2,翻转区间s1(l, r)使s1=s2,限定(r>=l),问可翻转区间个数
思路:
分类讨论:
1、存在不相同字符
步骤:① 找到存在不相同字符的最大区间,验证s1和s2在该区间内的对称性
② 如果满足对称性则向两边扩散,统计个数
复杂度:O(n)
2、不存在相同字符,即s1 = s2
其实就是求s1串的回文串总个数,跑一遍马拉车(manacher)板子
复杂度:O(n)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char s1[2000005], s2[2000005];
// 构造字符串数组
char s_new[4000005];
//
int len[4000005];
// 构造马拉车数组
int init(char str[])
{
// 加了会超时
//memset(len, 0, sizeof(len));
int n=strlen(str);
for(int i=1,j=0;i<=2*n;j++,i+=2)
{
s_new[i]='#';
s_new[i+1]=str[j];
}
s_new[0]='$';
s_new[2*n+1]='#';
s_new[2*n+2]='@';
s_new[2*n+3]='\n';
return 2*n+1;
}
// 求回文个数
ll manacher(int n)
{
ll ans = 0;
int mx=0,p=0;
for(int i=1;i<=n;i++)
{
if(mx>i)len[i]=min(mx-i,len[2*p-i]);
else len[i]=1;
while(s_new[i-len[i]]==s_new[i+len[i]])len[i]++;
if(len[i]+i>mx)mx=len[i]+i,p=i;
ans += (ll)len[i]/2;
}
return ans;
}
int min(int x, int y)
{
if(x>y)
return y;
return x;
}
int max(int x, int y)
{
if(x>y)
return x;
return y;
}
int main()
{
int t ;
scanf("%d", &t);
while(t--)
{
scanf("%s%s", s1, s2);
int len_s1 = strlen(s1);
int s, e, flag = 0;
s = len_s1, e = 0;
for(int i=0; i<len_s1; i++)
{
if(s1[i] != s2[i])
{
flag = 1;
// 找到第一个不相同的位置
s = min(s, i);
// 找到最后一个不相同的位置
e = max(e, i);
}
}
// 存在不相等区间
if(flag)
{
bool ymk = true;
int l = s, r = e;
int p = r-l+1;
// 验证不相等区间的对称性
while(p--)
{
if(s1[l] != s2[r])
{
ymk = false;
break;
}
l++, r--;
}
// 不对称直接退出
if(!ymk)
{
printf("0\n");
continue;
}
ll ans = 1;
s--, e++;
// 如果对称需要向两边扩散
while(1)
{
// 坐标约束
if(s<0 || e>=len_s1)
break;
// 对称性约束
if(s1[s] == s2[e] && s1[e] == s2[s])
{
ans++;
s--, e++;
}
else
break;
}
printf("%lld\n", ans);
}
// s1 = s2,跑一遍马拉车求回文个数
else
{
printf("%lld\n", manacher(init(s1)));
}
}
}
笔者水平有限,若有错误欢迎纠正