【Hash】【二分】ANT-Antisymmetry

LinkLink

luoguluogu P3501P3501

DescriptionDescription

對於一個01字符串,如果將這個字符串0和1取反後,再將整個串反過來和原串一樣,就稱作“反對稱”字符串。比如00001111和010101就是反對稱的,1001就不是。

現在給出一個長度爲N的01字符串,求它有多少個子串是反對稱的。

InputInput

第一行有個NN,第二行有個長度爲NN的字符串

OutputOutput

輸出如題意

SampleSample InputInput

8
11001011

SampleSample OutputOutput

7

HintHint

7個反對稱子串分別是:01(出現兩次),10(出現兩次),0101,1100和001011

TrainTrain ofof ThoughtThought

對於一個字符串的位置ii而言
它向左和向右拓展k格若是一個迴文串,那麼拓展k-1格也必定是一個迴文串,我們只需要二分這個k,然後每次判斷是否爲迴文就可以了

CodeCode

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;

string s; ll ans;
const int math = 11;
ll re[1000005], hash[1000005], hashback[1000005];

bool check(int x, int y, int midx)
{
	int hash1 = hash[x + midx - 1] - hash[x - 1];
	int hash2 = hashback[y  + midx - 1] - hashback[y - 1];
	
	if (x > y) {
		swap(hash1, hash2);
		swap(x, y);
	}
	
	hash1 *= re[y - x];
	return hash1 == hash2; 
}
int main()
{
	int n;
	cin >> n;
	cin >> s;
	re[0] = 1;
	for (int i = 1; i <= n; ++i) 
		re[i] = re[i - 1] * math; //
	for (int i = 1; i <= n; ++i)
		hash[i] = hash[i - 1] + s[i - 1] * re[i]; //算哈希值
		
	for (int i = 1; i <= n >> 1; ++i)
	 	swap(s[i - 1], s[n - i]);
	for (int i = 1; i <= n; ++i)
		if (s[i - 1] == '0') s[i - 1] = '1';
	    	else s[i - 1] = '0';//翻轉字符串
	
	for (int i = 1; i <= n; ++i)
    	hashback[i] = hashback[i - 1] + s[i - 1] * re[i];//算翻轉後的字符串的哈希值
	for (int i = 2; i <= n; ++i) {
		int maxn=0; 
    	int j = n - i + 2;
    	int l = 1, r = min(n - i + 1, n - j + 1);
    	while (l <= r)
    	{
    		int mid = (l + r) >> 1;
    		if (check(i, j, mid)) 
    			maxn = max(maxn, mid),l=mid+1;
    		 	 else r=mid-1;
    	}
    	ans += maxn;
	}
	
	printf("%lld", ans);
	return 0;
}

AfterAfter thethe texttext

其實我可以很快敲完代碼的。。。
就是被師兄要求的碼風坑了很久。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章