洛谷 P3501 [POI2010]ANT-Antisymmetry

目录:


题目:

传送门


分析:

一个反对称串就是将这个串取反然后放在原串后面的话是回文串,然后回文串是满足单调性的(如果以一个点为中心扩展 k 格是回文串,那么扩展 k 1 格也是回文串),所以我们可以枚举中心,然后二分最大的 k ,然后用 h a s h 判断回文。


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>  
#include<cstdlib>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#define LL long long
#define ull unsigned long long
using namespace std;
const ull bace=2000001001;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
ull king[500001],h[500001],hr[500001];
int min(int x,int y)
{
    return x<y? x:y;
}
int max(int x,int y)
{
    return x>y? x:y;
}
bool check(int l,int r,int x)
{
    ull s1,s2;
    s1=h[l+x-1]-h[l-1];
    s2=hr[r+x-1]-hr[r-1];
    if(l>r) swap(l,r),swap(s1,s2);
    s1*=king[r-l];
    return s1==s2;
}
int main()
{
    int n=read();
    char s[500001];
    scanf("%s",&s);
    king[0]=1;
    for(int i=1;i<=n;i++) king[i]=king[i-1]*bace; 
    for(int i=1;i<=n;i++)
      h[i]=h[i-1]+s[i-1]*king[i];
    for(int i=1;i<=n/2;i++) swap(s[i-1],s[n-i]);
    for(int i=1;i<=n;i++)
      if(s[i-1]=='0') s[i-1]='1';
      else s[i-1]='0';
    for(int i=1;i<=n;i++)
      hr[i]=hr[i-1]+s[i-1]*king[i];
    long long ans=0;
    for(int i=2;i<=n;i++)
    {
        int l=1,r=min(n-i+1,i-1);
        int maxn=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(i,n-i+2,mid)) maxn=max(maxn,mid),l=mid+1;
            else r=mid-1;
        }
        ans+=maxn;
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/81748907