【哈希和哈希表】Antisymmetry

本文介绍了一种使用哈希技巧高效求解给定0/1字符串中反对称子串数量的方法。反对称子串是指取反并反转后与原串相等的子串。文章详细阐述了通过枚举前半部分最后一个位置,并利用二分搜索和哈希值进行匹配,从而快速找出所有符合条件的子串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

转载于:https://www.cnblogs.com/czy-power/p/10357495.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值