Strings in the Pocket
- 时间:1000 ms
- 内存:65536 kB
题意:
有两个字符串s和t,可以对s的一个区间进行一次操作,使得这个区间里的字符的顺序反转。如果只能进行一次这个操作,问对于给定的s和t,有多少种不同的方法操作s,使得s和t相同?
思路:
1、如果s和t有一段子串(l,r)不同,且(l,r)之外的部分相同,那么对这个子串进行操作应该会使s和t相同,不然就没有解;如果(l,r)是一个解,且l-1与r+1处的字符相同,那么(l-1,r+1)也是一个解,一直向两端扩展,直到某端到头或者两端字符不相同为止。
2、如果s个t相同,那么我们可以对s的任意回文子串进行操作,这样s和t依旧相同,问题转化为问s中一共多少个回文子串,此处可以用Manacher算法。
题目来源:The 16th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2000006;
char s[maxn],t[maxn],sub_s[maxn],sub_t[maxn];
//马拉车算法
//---------------------------------------------
char ma_s[2*maxn];
int ma_len[2*maxn];
int init(char *str,char *s)
{
int n=strlen(str);
for(int i=1,j=0;i<=2*n;j++,i+=2)
{
s[i]='#';
s[i+1]=str[j];
}
s[0]='$';
s[2*n+1]='#';
s[2*n+2]='@';
s[2*n+3]='\n';
return 2*n+1;
}
void manacher(int n,char *s,int *len)
{
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[i-len[i]]==s[i+len[i]])len[i]++;
if(len[i]+i>mx)mx=len[i]+i,p=i;
}
}
//求子串数量
ll countSubstrings(char *p,char *s,int *len)
{
int n=init(p,s);
for(int i = 0; i < n; ++i)
len[i]=0;
manacher(n,s,len);
ll ans=0;
for(int i=1;i<=n;i++)
ans+=len[i]/2;
return ans;
}
//------------------------------------------------
ll countDefferent(char *s,char *t,int len,char *sub_s,char *sub_t)
{
int st,ed;
for(int i = 0; i < len; ++i)
{
if(s[i]!=t[i])
{
st = i;
break;
}
}
for(int i = len-1; i>=0; --i)
{
if(s[i]!=t[i])
{
ed = i;
break;
}
}
int sub_len=0;
for(int i = st; i <= ed; ++i)
{
sub_s[sub_len] = s[i];
sub_t[sub_len++] = t[i];
}
sub_s[sub_len]='\0';
sub_t[sub_len]='\0';
reverse(sub_t,sub_t+sub_len);
if(strcmp(sub_s,sub_t)==0)
{
ll ans = 1;
st--;
ed++;
while(st>=0&&ed<len&&s[st--]==s[ed++]) ans++;
return ans;
}
return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s%s",s,t);
int s_len = strlen(s);
int t_len = strlen(t);
if(s_len!=t_len)
printf("0\n");
else if(strcmp(s,t)==0)
printf("%lld\n",countSubstrings(s,ma_s,ma_len));
else
printf("%lld\n",countDefferent(s,t,s_len,sub_s,sub_t));
}
return 0;
}