問題 H: 【雜湊和雜湊表】Antisymmetry
阿新 • • 發佈:2018-11-12
問題 H: 【雜湊和雜湊表】Antisymmetry
時間限制: 1 Sec 記憶體限制: 128 MB
提交: 26 解決: 5
[提交] [狀態] [討論版] [命題人:admin]
題目描述
對於一個0/1字串,如果將這個字串0和1取反後,再將整個串反過來和原串一樣,就稱作「反對稱」字串。比如00001111和010101就是反對稱的,而1001就不是。
現在給出一個長度為n的0/1字串,求它有多少個子串是反對稱的,注意這裡相同的子串出現在不同的位置會被重複計算。
輸入
第一行一個正整數n。
第二行一個長度為n的0/1字串。
輸出
一行一個整數,表示原串的反對稱子串個數。
樣例輸入
8
11001011
樣例輸出
7
提示
對於100%的資料,1≤n≤500000。
mdzz,忘記打表了,一直超時
給p^i,打個表,就過了。。。。
這題,二分+hash,一開始迴文串搞錯了,後來二分炸了,再後來一直超時。。。多災多難
反對稱,奇數串肯定不行,最中間那個一取反就壞了,所以一定是偶數串,然後取反一半,恰好與另一半映象,
也就是迴文串了
那麼5e5,複雜度也是n*logn之類的
那麼想到二分,列舉子串中心位置,二分子串長度。。注意二分的時候還有個小技巧,
就是拿一個變數存長度最大的可能值
再然後就是注意打一個p的i次方的表,因為反覆呼叫導致超時
要沒有這篇部落格我可能要死上個四五天也出不來。。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ull,ull> pull; const int maxn = 6e5+7; const pull p{131LL,13331LL},one{1LL,1LL},zero{0LL,0LL}; inline pull operator - (pull a,pull b){return make_pair((a.first - b.first),(a.second - b.second));} inline pull operator * (pull a,pull b){return make_pair((a.first * b.first),(a.second * b.second));} inline pull operator + (pull a,pull b){return make_pair((a.first + b.first),(a.second + b.second));} inline pull operator + (pull a,int b){return make_pair((a.first + b ),(a.second + b ));} char a[maxn]; pull Len[maxn],invLen[maxn],Pw[maxn]; bool id(char x){ return x-'0'; } pull Strcut(pull *Len,int l,int r){ return Len[r] - Len[l-1]*Pw[r-l+1]; } pull invStrcut(pull *Len,int l,int r){ return Len[l] - Len[r+1]*Pw[r-l+1]; } int main(){ Pw[0] = one; for(int i=1;i<maxn;i++)Pw[i] = Pw[i-1]*p; int n; scanf("%d",&n); scanf("%s",a+1); Len[0] = invLen[n+1] = zero; for(int i=1;i<=n;i++){ Len[i] = Len[i-1]*p + id(a[i]); invLen[n-i+1] = invLen[n-i+2]*p + !id(a[n-i+1]); } int l,r,mid,sul; ll ans = 0; for(int i=1;i<n;i++){ l = 0,r = min(i,(n-i)); while(l<=r){ mid = (l+r)/2; if(Strcut(Len,i-mid+1,i) == invStrcut(invLen,i+1,i+mid)) l = mid+1,sul = mid; else r = mid-1; } ans += sul; } printf("%lld\n",ans); return 0; }
過了之後,瞎幾把測試,於是,單hash,並且用的無符號int
9312 |
84 |
上面那個雙hash 的
30408 |
144 |
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int maxn = 6e5+7;
const uint p = 13331;
char a[maxn];
uint Len[maxn],invLen[maxn],Pw[maxn];
bool id(char x){
return x-'0';
}
uint Strcut(int l,int r){
return Len[r] - Len[l-1]*Pw[r-l+1];
}
uint invStrcut(int l,int r){
return invLen[l] - invLen[r+1]*Pw[r-l+1];
}
int main(){
Pw[0] = 1;
for(int i=1;i<maxn;i++)
Pw[i] = Pw[i-1]*p;
int n;
scanf("%d",&n);
scanf("%s",a+1);
Len[0] = invLen[n+1] = 0;
for(int i=1;i<=n;i++){
Len[i] = Len[i-1]*p + id(a[i]);
invLen[n-i+1] = invLen[n-i+2]*p + !id(a[n-i+1]);
}
int l,r,mid,sul;
ll ans = 0;
for(int i=1;i<n;i++){
if(a[i]==a[i+1])continue;
l = 1,r = min(i,(n-i));
while(l<=r){
mid = (l+r)/2;
if(Strcut(i-mid+1,i) == invStrcut(i+1,i+mid))
l = mid+1,sul = mid;
else
r = mid-1;
}
ans += sul;
}
printf("%lld\n",ans);
return 0;
}