运气最差的一集--神秘哈希
T1
这道题很简单。不过因为我手动把整数数组改成了字符数组去搞哈希,然后只拿了90分
这道题只是一个普通的哈希题,核心代码就一小段:
unsigned long long get_hash(int l,int r)
{
return hs[r]-hs[l-1]*pw[r-l+1];
}
是真的,我们只需要把输入的转成哈希值,二分枚举重复不少于
T2
un get_hash(int l,int r)
{
return hs[r]-hs[l-1]*pw[r-l+1];
}
un get_hash_r(int l,int r)
{
return ht[l]-ht[r+1]*pw[r-l+1];
}
un表示unsigned long long。只要使用这两段函数,我们用
for(int i=1;i<s.size();i++)
{
for(int j=i;j<s.size();j++)
{
for(int l=j+1;l<s.size();l++)
{
for(int r=l;r<s.size();r++)
{
if(get_hash(i,j)==get_hash_r(i,j)&&get_hash(l,r)==get_hash_r(l,r))
{
cnt++;
}
}
}
}
}
但是,这显然不够,还能优化。
- 维护
cnt[i] 表示以点i 开头的回文串的数量 - 维护
suf[i] 表示从点i 以及i 之后开头的回文串的数量。suf[i]=suf[i+1]+cnt[i] - 枚举
[l1,r1] 命名为A 串,那么与A 串形成四元组的字符串有suf[r1+1] 个
那我们二重循环,
T3
写这题是答案没开long long,炸了,本来可以全对的。
我们不妨先找出已经回文的前后缀长度
我们可以考虑删除子串
T4
这道题不过是把回文串包装成了反对称,感觉和前面的题难度差不多。
我们仔细想一想,如果一个字符串在区间
也就是说,区间
所以,我们不妨枚举回文字符串的对称轴,然后二分它能向左右延伸的最大长度
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,base=13331;
int n;
unsigned long long hs[N],ht[N],pw[N];
string s;
unsigned long long get_hash(unsigned long long h[],int l,int r)
{
return h[r]-h[l-1]*pw[r-l+1];
}
unsigned long long get_hash_r(unsigned long long h[],int l,int r)
{
return h[l]-h[r+1]*pw[r-l+1];
}
bool check(int x,int len)
{
int st=x-len+1,ed=x+len;
return get_hash(hs,st,ed)==get_hash_r(ht,st,ed);
}
int main()
{
cin>>n>>s;
s=" "+s;
for(int i=1;i<=n;i++)
hs[i]=hs[i-1]*base+(s[i]=='1');
for(int i=n;i>=1;i--)
ht[i]=ht[i+1]*base+(s[i]=='0');
pw[0]=1;
for(int i=1;i<=n;i++)
pw[i]=pw[i-1]*base;
long long ans=0;
for(int i=1;i<n;i++)
{
int l=0,r=min(i,n-i)+1;
while(l+1<r)
{
int mid=(l+r)/2;
if(check(i,mid)==true)
l=mid;
else
r=mid;
}
ans+=l;
}
cout<<ans;
}