Strings in the Pocket(2019浙江省省賽)(馬拉車-Manacher)

Strings in the Pocket(2019浙江省省賽)(馬拉車-Manacher)

Time limit:1000 ms
Memory limit:65536 kB
judge:
ZOJ
vjudge

Description

BaoBao has just found two strings s=s1s2sns = s_1s_2\dots s_n and t=t1t2tnt = t_1t_2\dots t_n in his left pocket, where sis_i indicates the ii-th character in string ss, and tit_i indicates the ii-th character in string tt.

As BaoBao is bored, he decides to select a substring of ss and reverse it. Formally speaking, he can select two integers ll and rr such that 1lrn1 \le l \le r \le n and change the string to s1s2sl1srsr1sl+1slsr+1sn1sns_1s_2\dots s_{l-1}s_rs_{r-1} \dots s_{l+1}s_ls_{r+1}\dots s_{n-1}s_n.

In how many ways can BaoBao change ss to tt using the above operation exactly once? Let (a,b)(a, b) be an operation which reverses the substring sasa+1sbs_as_{a+1} \dots s_b, and (c,d)(c, d) be an operation which reverses the substring scsc+1sds_cs_{c+1} \dots s_d. These two operations are considered different, if aca \ne c or bdb \ne d.

Input

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

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

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

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

題意

給你兩個字符串 sstt ,你可以選擇 ss 的一個區間,然後區間內的元素左右翻轉。此操作只能執行一次。問你有多少種操作可以使 ss 變爲 tt

題解

假設 ss 可以變爲 tt (廢話)

那麼還要分類討論一下

  1. ss 不等於 tt 時,此時 sstt 一定有一段區間可以通過反轉來變爲 tt 的對應區間。那麼這一段區間就是一種答案。此外一次區間爲基準向外擴展,因爲如果此區間外左右兩邊的元素相同的話換與不換都不影響結果,所以包含他們就又是一種答案,以此類推,外面有幾層相同的,答案就加幾。
    在這裏插入圖片描述
  2. ss 等於 tt 時,我們可以找到一個迴文子串,然後反轉這個區間,效果就相當於沒反轉,那麼 sstt 還是相同的。所以問題就轉化爲了求 ss 的迴文子串的數目。
    由此想到了馬拉車算法,因爲p數組的意義就是以當前位置爲中心的迴文串的最大寬度。那麼寬度就是迴文串的半徑,也就是可以組成的迴文串的個數。但是由於馬拉車算法往字符裏塞了一些特殊字符,所以對p[i]/2求和即可。
    在這裏插入圖片描述

代碼

#include <iostream>
#include <cstring>
#define maxn 4000005
using namespace std;

int p[maxn];
int T;
char str[maxn / 2], ttr[maxn / 2];
char ss[maxn];

long long manacher() {
	int len = 0;
	ss[len++] = '$';
	ss[len++] = '#';
	int n = strlen(str);
	for (int i = 0; i < n; i++) {
		ss[len++] = str[i];
		ss[len++] = '#';
	}
	int mx = 0, id = 0;
	for (int i = 1; i < len; i++) {
		if (mx > i) p[i] = (p[2 * id - i] < (mx - i) ? p[2 * id - i] : (mx - i));
		else p[i] = 1;
		while (i - p[i] >= 0 && i + p[i] < len && ss[i - p[i]] == ss[i + p[i]]) p[i]++;
		if (i + p[i] > mx) {
			mx = i + p[i];
			id = i;
		}
	}
	long long ans = 0;
	for (int i = 2; i < len - 1; ++i) {
		if (ss[i] == '#') ans += p[i] / 2;
		else ans += (p[i] + 1) / 2;
	}
	return ans;
}

int getno() {
	int ans = 1, len = strlen(str);
	int l = 0, r = len - 1;
	while (l < r && str[l] == ttr[l]) ++l;
	while (r > l && str[r] == ttr[r]) --r;
	for (int i = l, j = r; i <= r; ++i, --j) if (str[i] != ttr[j]) return 0;
	for (int i = l - 1, j = r + 1, le = len; i >= 0 && j < le && str[i] == ttr[j]; --i, ++j) ++ans;
	return ans;
}

int main() {
	while (cin >> T) {
		for (int i = 0; i < T; ++i) {
			scanf("%s%s", str, ttr);
			if (strcmp(str, ttr) == 0) cout << manacher() << "\n";
			else cout << getno() << "\n";
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章