【二分】【哈希】ANT-Antisymmetry

ANT-Antisymmetry

題目

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

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

輸入

第一行n
第二行n個01字符串

輸出

它有多少個子串是反對稱的

輸入樣例

8
11001011

輸出樣例

7

解題思路

其實這道題就是一道哈希加二分,推出來可以得出反過來的01串加上原本的可以發現是一個迴文,那麼就很好解決了。枚舉中心,不斷的看k格,然後就哈希看是否爲迴文即可.

程序如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long 
const ll math=2000001001;
using namespace std;
int n,j,l,r,mid,maxn;
ll hx[500001],re[500001],hxx[500001],ans;
char a[500001];
bool check(int l,int r,int m)
{ 
	ll s1,s2;
	int h1,h2;
	h1 = l + m - 1;
	h2 = r + m - 1;
	s1 = hx[h1] - hx[l - 1];//看是否爲迴文
	s2 = hxx[h2] - hxx[r - 1];
	if(l > r)
	{
		swap(s1,s2);
		swap(l,r);
	}
	s1 *= re[r - l];
	return s1 == s2;
}
int main()
{
	scanf("%d",&n);
	scanf("%s",&a);
	re[0]=1;
	for(int i = 1;i <= n;++ i) 
	   re[i] = re[i - 1] * math;
	for(int i = 1;i <= n;++ i)
	   hx[i] = hx[i - 1] + a[i - 1] * re[i];//把字符串轉化成數值
	for(int i = 1;i <= n / 2;++ i) 
	   swap(a[i - 1],a[n - i]);//交換兩邊的
	for(int i = 1;i <= n;++ i)
	   if(a[i - 1] == '0') a[i - 1] = '1';//改變
	   else a[i - 1] = '0';
	for(int i = 1;i <= n;++ i)
	   hxx[i] = hxx[i - 1] + a[i - 1] * re[i];
	for(int i = 2;i <= n;++ i)
	{
		j = n - i + 2;
		l = 1;
		r = min(n - i + 1,n - j + 1);
		maxn=0;
		while(l <= r)//二分
		{
			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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章