问题 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;
}