【manacher】Strings in the Pocket

Strings in the Pocket

Time Limit: 1 Second Memory Limit: 65536 KB
BaoBao has just found two strings s = s 1 s 2 … s n s=s_1s_2\dots s_n s=s1s2sn and t = t 1 t 2 … t n t=t_1t_2\dots t_n t=t1t2tn in his left pocket, where s i s_i si indicates the i i i-th character in string , and t i t_i ti indicates the i i i-th character in string t t t.

As BaoBao is bored, he decides to select a substring of and reverse it. Formally speaking, he can select two integers l l l and r r r such 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrnthat and change the string to s 1 s 2 … s l − 1 s r s r − 1 … s l + 1 s l s r + 1 … s n − 1 s n s_1s_2\dots s_{l-1}s_rs_{r-1}\dots s_{l+1}s_ls_{r+1}\dots s_{n-1}s_n s1s2sl1srsr1sl+1slsr+1sn1sn.

In how many ways can BaoBao change to using the above operation exactly once? Let ( a , b ) (a,b) (a,b) be an operation which reverses the substring s a s a + 1 … s b s_as_{a+1}\dots s_b sasa+1sb, and ( c , d ) (c,d) (c,d) be an operation which reverses the substring s c s c + 1 … s d s_cs_{c+1}\dots s_d scsc+1sd. These two operations are considered different, if a = ̸ c a=\not c a≠c or b = ̸ d b=\not d b≠d.

Input

There are multiple test cases. The first line of the input contains an integer T T T, indicating the number of test cases. For each test case:

The first line contains a string s ( 1 ≤ ∣ s ∣ ≤ 2 × 1 0 6 ) s(1\le |s| \le 2 \times 10^6) s(1s2×106), while the second line contains another string t ( ∣ t ∣ = ∣ s ∣ ) t(|t| = |s|) t(t=s). Both strings are composed of lower-cased English letters.

It’s guaranteed that the sum of ∣ s ∣ |s| s of all test cases will not exceed 2 × 1 0 7 2 \times 10^7 2×107.

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).

题目大意:

先输入一个整数 t t t,代表共有 t t t组测试样例,对于每一组测试样例,输入两个字符串 s 1 , s 2 s_1,s_2 s1,s2,现在仅能将字符串 s 1 s_1 s1中的某个字串翻转 s 1 s_1 s1 s 2 s_2 s2相等,问共有几中反转方法。

解题思路:

此题可以将题目分为两种情况,一种是字符串 s 1 s_1 s1与字符串 s 2 s_2 s2完全相同,对于这种情况,可以通过manacher来计算字符串 s i s_i si中每个回文串的长度,将长度求和即为总的方案数,对于 s 1 s_1 s1 s 2 s_2 s2不等的情况,可以先从左往右找到 s 1 s_1 s1 s 2 s_2 s2第一个不同的位置 l l l,同理,从右往左找到两字符串第一次不同的位置 r r r,先判断 s 1 s_1 s1的字串 s l s l + 1 … s r − 1 s r s_ls_{l+1}\dots s_{r-1}s_r slsl+1sr1sr反转后是否会使 s 1 s_1 s1 s 2 s_2 s2完全相同,不会的话证明无法在反转一次的情况下使两字符串相同,输出 0 0 0,否则则以此字串为边界同时往两边扩展,判断字串长度是否能延伸,记录输出即可。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e5 + 5;
const ll mod = 1e9+7;
string s1,s2,s1_new;
int p[6004000];
int get_newstring() {
	s1_new.clear();
	int len=s1.size();
	s1_new+='$';
	for(int i=0;i<len;i++) {
		s1_new+='#';
		s1_new+=s1[i];
	}
	s1_new+='#';
	return s1_new.size();
}
ll manacher() {
	int len=get_newstring();
	fill(p,p+len,0);
	int id=0,mx=0;
	ll ans=0;
	for(int i=0;i<len;i++) {
		if(i<mx) 
			p[i]=min(p[2*id-i],mx-i);
		else
			p[i]=1;
		while(s1_new[i-p[i]]==s1_new[i+p[i]]) {
			p[i]++;
		}
		if(p[i]+i>mx) {
			mx=i+p[i];
			id=i;
		}
		 ans+=(ll)(p[i]/2);
	}
	return ans;
}
int main() 
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    #endif
    //freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(0),cin.tie(0);
    int t;
    cin>>t;
    while(t--) {
    	cin>>s1>>s2;
    	ll ans=0;
    	if(s1==s2) {
    		ans=manacher();
    	}
    	else {
    		int l=0,r=s1.size()-1;
    		while(s1[l]==s2[l]) l++;
    		while(s1[r]==s2[r]) r--;
    		bool ju=false;
    		int t1=l,t2=r;
    		while(s1[t1]==s2[t2]) {
    			if(t1==r&&t2==l) break;
    			t1++;t2--;
    		}
    		if(t2==l&&t1==r) {
    			ju=true;
    		}
    		else ju=false;
    		if(l==r) ju=false;
    		if(ju==true) {
    			ans=1;
                l--,r++;
    			while(l>=0&&r<s1.size()&&s1[l]==s2[r]&&s1[r]==s2[l]) {
    				ans++;
    				l--;
    				r++;
    			}

    		}
    		else ans=0;
    	}
    	cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值