ZOJ 4110 Strings in the Pocket (马拉车+回文串)
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4110
题目:
BaoBao has just found two strings and in his left pocket, where indicates the -th character in string , and indicates the -th character in string .
As BaoBao is bored, he decides to select a substring of and reverse it. Formally speaking, he can select two integers and such that and change the string to .
In how many ways can BaoBao change to using the above operation exactly once? Let be an operation which reverses the substring , and be an operation which reverses the substring . These two operations are considered different, if or .
Input
There are multiple test cases. The first line of the input contains an integer , indicating the number of test cases. For each test case:
The first line contains a string (), while the second line contains another string (). Both strings are composed of lower-cased English letters.
It's guaranteed that the sum of of all test cases will not exceed .
Output
For each test case output one line containing one integer, indicating the answer.
Sample Input
2 abcbcdcbd abcdcbcbd abc abc
Sample Output
3 3
Hint
For the first sample test case, BaoBao can do one of the following three operations: (2, 8), (3, 7) or (4, 6).
For the second sample test case, BaoBao can do one of the following three operations: (1, 1), (2, 2) or (3, 3).
题意:
存在S串和T串 要求对S串的一个子串做一次翻转操作可以得到T串的方案数
思路:
对子串分两种情况
第一种是S串和T串完全相同 可以的方案数就是S串中的所有的回文子串 因为S串长度为2e6 必须要用马拉车线性去处理出所有的回文子串
第二种是S串和T串有不同的部分 找出两个不同的字符最远的位置(l,r) 先判断S串的这个区间是否能通过翻转变成T串的区间 如果不可以直接输出0 如果可以 则向两侧同时延展寻找是否可以翻转
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e6+100; int t,len[maxn*2]; char S[maxn],T[maxn],s[maxn*2]; int init(char *str){ 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){ 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; } } int main(){ scanf("%d",&t); while(t--){ scanf("%s",S); scanf("%s",T); int Len=strlen(S),tot1=-1,tot2=Len; for(int i=0;i<Len;i++){ if(S[i]!=T[i]){ tot1=i;break; } } for(int i=Len-1;i>=0;i--){ if(S[i]!=T[i]){ tot2=i;break; } } if(tot1==-1){ int n=init(S); for(int i=0;i<=n;i++) len[i]=0; manacher(n); ll ans=0; for(int i=1;i<=n;i++) ans+=len[i]/2; printf("%lld\n",ans); continue; } else{ int tmp=0; for(int i=tot1;i<=tot2;i++){ if(S[i]!=T[tot2-(i-tot1)]){ tmp=1; break; } } if(tmp==1){ printf("0\n"); continue; } else{ ll ans=1; tot1--; tot2++; while (tot1>=0 && tot2<Len && S[tot1]==T[tot2] && S[tot2]==T[tot1]){ tot1--; tot2++; ans++; } printf("%lld\n",ans); } } } return 0; }