【哈希和哈希表】Antisymmetry
阿新 • • 發佈:2019-02-09
tex string default fault its -m NPU bit 數據
提交: 36 解決: 12
[提交] [狀態] [討論版] [命題人:admin]
現在給出一個長度為n的0/1字符串,求它有多少個子串是反對稱的,註意這裏相同的子串出現在不同的位置會被重復計算。
第二行一個長度為n的0/1字符串。
問題 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; #defineREP(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