BZOJ 2084 二分+hash OR Manacher

思路:

二分+哈希

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=500050;
const ll mod=1000000007;
int n;
ll hs1[N],hs2[N],base[N],Ans;
char s1[N],s2[N];
int main(){
    scanf("%d",&n);
    scanf("%s",s1+1),base[0]=1;
    for(int i=1;i<=n;i++)
        hs1[i]=(hs1[i-1]*50+s1[i])%mod,
        s2[i]=s1[i]==‘1‘?‘0‘:‘1‘,base[i]=base[i-1]*50%mod;
    for(int i=n;i;i--)hs2[i]=(hs2[i+1]*50+s2[i])%mod;
    for(int i=1;i<n;i++){
        int l=0,r=min(n-i,i),ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(((hs1[i]-hs1[i-mid]*base[mid]%mod)+mod)%mod==((hs2[i+1]-hs2[i+mid+1]*base[mid]%mod)+mod)%mod)
                l=mid+1,ans=mid;
            else r=mid-1;
        }
        Ans+=ans;
    }printf("%lld\n",Ans);
}

Manacher改一下条件

0只能匹配1  1只能匹配0 #匹配#

(长度从0开始匹配  这样就相当于只能从#开始走了 也就是长度为偶数)

//By SiriusRen
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1000050;
ll ans;
int n,p[N];
char s[N],ch[N];
bool cmp(char x,char y){return (x==‘#‘&&y==‘#‘)||(x==‘1‘&&y==‘0‘)||(x==‘0‘&&y==‘1‘);}
void Manacher(){
    int mx=0,id=0;
    for(int i=1;i<=n;i++){
        if(mx>i)p[i]=min(p[id*2-i],p[id]+id-i);
        else p[i]=0;
        while(cmp(s[i-p[i]],s[i+p[i]]))p[i]++;
        if(i+p[i]>mx)mx=i+p[i],id=i;
        ans+=p[i]/2;
    }
}
int main(){
    scanf("%d",&n);
    scanf("%s",ch+1);
    s[1]=‘#‘;
    for(int i=1;i<=n;i++)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
    n=n<<1|1;Manacher();
    printf("%lld\n",ans);
}
时间: 2024-12-28 08:36:26

BZOJ 2084 二分+hash OR Manacher的相关文章

BZOJ 2084 [Poi2010]Antisymmetry(manacher)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2084 [题目大意] 对于一个01字符串,如果将这个字符串0和1取反后, 再将整个串反过来和原串一样,就称作“反对称”字符串. 比如00001111和010101就是反对称的,1001就不是. 现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. [题解] 修改manacher的判定条件,对该串进行计算即可. [代码] #include <cstdio> #include

【BZOJ1414/3705】[ZJOI2009]对称的正方形 二分+hash

[BZOJ1414/3705][ZJOI2009]对称的正方形 Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数. Orez自然很想知道这个数是多少,可是矩阵太大,无法去数.只能请你编个程序来计算出这个数. Input 文件的第一行为两个整数n和m.接下来n行每行包含m个正整数,表示Or

UVA - 12338 Anti-Rhyme Pairs 二分+hash

题目链接:https://vjudge.net/problem/UVA-12338 题意: 给你n个串 问你任意两个串的最大公共前缀长度是多少 题解: 二分+hash 思路很明显,我最近用来写hash 很鸡肋 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls

【二分+hash】【字符串】【平衡树】【JSOI 2008】火星人prefix

1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MB Submit: 4264 Solved: 1306 Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人定义了一个函数LCQ(x, y)

BZOJ-1014 [JSOI2008]火星人prefix (Splay+二分+hash)

题解: 用splay维护添加修改操作,然后二分hash判断长度. 操作一:对于查询区间[l,r]的hash值,显然将l-1旋到根,将r+1旋到根的右儿子,此时所求区间就是根的右儿子的左儿子了. 操作二:将要修改的位置旋到根,然后直接改就可以了. 操作三:要在x后面添加一个字符,显然将x旋到根,x+1旋到根的右儿子,然后直接加在根的右儿子的左儿子上就可以了. 1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio&g

FJUT3703 这还是一道数论题(二分 + hash + manacher)题解

Problem Description 最后来个字符串签个到吧,这题其实并不难,所需的算法比较基础,甚至你们最近还上过课. 为了降低难度,免得所有人爆零.这里给几个提示的关键字 :字符串,回文,二分,哈希. 注意要对奇偶回文分开二分 这样还不会做,说明基础有所欠缺. 给你一个字符串A和一个字符串B,请你求一个满足以下要求的所有字符串中,最长的字符串C的长度: C必须同时是A和B的子串,即A和B中都必须存在一个子区间和C长得一样 C必须是一个回文,即正过来读和反过来读都一样 Input 多组数据,

bzoj 1014 LCP 二分 Hash 匹配

求同一字符串的两个后缀的最长公共前缀. 将字符串按位置放到Splay中维护(每个节点还维护一下该子树的hash),然后二分前缀的长度,用splay计算出指定范围的hash,按hash是否相等来判断是否相同. 一开始是将字符串看成26进制,加上unsigned long long的自然溢出来计算哈希,但这样Wa掉了,改成27进制就AC了,但我还不知道为什么,望明者相告,谢. 1 /***********************************************************

bzoj 1014[JSOI2008]火星人prefix - 二分 + hash + splay

我们发现要支持修改操作,所以后缀数组就不适用了 查询两个字符串的lcp有两个很常见的算法, 后缀数组和 二分哈希 所以对于字符串的修改我们用一个splay 来维护, 平衡树每个节点表示的是对应子树的字符串的哈希值. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define LL long long 6 using namesp

bzoj 2084: [Poi2010]Antisymmetry -- manacher

2084: [Poi2010]Antisymmetry Time Limit: 10 Sec  Memory Limit: 259 MB Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串.比如00001111和010101就是反对称的,1001就不是.现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. Input 第一行一个正整数N (N <= 500,000).第二行一个长度为N的01字符串. Output