1. 程式人生 > >【哈希和哈希表】Antisymmetry

【哈希和哈希表】Antisymmetry

tex string default fault its -m NPU bit 數據

問題 H: 【哈希和哈希表】Antisymmetry

時間限制: 1 Sec 內存限制: 128 MB
提交: 36 解決: 12
[提交] [狀態] [討論版] [命題人:admin]

題目描述

對於一個0/1字符串,如果將這個字符串0和1取反後,再將整個串反過來和原串一樣,就稱作「反對稱」字符串。比如00001111和010101就是反對稱的,而1001就不是。
現在給出一個長度為n的0/1字符串,求它有多少個子串是反對稱的,註意這裏相同的子串出現在不同的位置會被重復計算。

輸入

第一行一個正整數n。
第二行一個長度為n的0/1字符串。

輸出

一行一個整數,表示原串的反對稱子串個數。

樣例輸入

8
11001011

樣例輸出

7

提示

對於100%的數據,1≤n≤500000。

思路:顯然符合條件的字串長度為偶數,否則中間那位取反後不可能與原串相同。

枚舉前半部分最後一個位置(1~n-1),二分長度hash即可。

#include<bits/stdc++.h>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ull unsigned long long;
#define
REP(i, a, b) for(int i = (a); i <= (b); ++ i) #define REP(j, a, b) for(int j = (a); j <= (b); ++ j) #define PER(i, a, b) for(int i = (a); i >= (b); -- i) const int maxn = 5e5 + 5; using namespace std; char str[maxn]; int n, a[maxn], b[maxn], gt; long long tot; int ha[maxn], hb[maxn], base
[maxn]; int funa(int l, int r) { return ha[r] - ha[l - 1] * base[r - l + 1]; } int funb(int l, int r) { return hb[l] - hb[r + 1] * base[r - l + 1]; } int main(){ cin >> n; base[0] = 1; scanf("%s", str+1); REP(i, 1, n)a[i] = str[i] - 0, b[i] = a[i] ^ 1; REP(i, 1, n)ha[i] = ha[i - 1] * 131 + a[i], base[i] = base[i - 1] * 131; PER(i,n,1)hb[i] = hb[i+1] * 131 + b[i]; for (int i = 1; i < n; i++) { int l = 1, r= min(i, n - i), mid; gt = 0; while (l <= r) { int mid = (l + r) / 2; if(funa(i-mid+1,i+mid)==funb(i-mid+1,i+mid))gt=mid,l=mid+1; else r = mid - 1; } tot += gt; } cout<<tot<<endl; }

【哈希和哈希表】Antisymmetry