码迷,mamicode.com
首页 > 其他好文 > 详细

Poi2010 Antisymmetry

时间:2019-08-27 19:09:24      阅读:89      评论:0      收藏:0      [点我收藏+]

标签:names   def   去掉   ace   temp   sdi   amp   %s   就是   

Antisymmetry

对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。

N <= 500,000

manacher

manacher匹配的时候改一下匹配条件就可以了,只要两个数相加等于一时就可以,一定要注意是不存在奇数串的,而且统计的时候要用long long,还要除以二。

时间复杂度\(O(n)\)

话说那个哈希+二分也可以过,利用一个反对称串长度一定为偶数,且后半段取反后形成回文串,不过实现和复杂度显然没有manacher更优。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>il T read(rg T&x)
{
    return x=read<T>();
}
typedef long long ll;

co int N=1e6+1;
char s[N],a[N*2];
int p[N*2];
int n,m;

void manacher()
{
    m=2*n+1;
    for(int i=1;i<=n;++i)
        a[i*2]=s[i],a[i*2+1]='#';
    a[0]='+',a[1]='#',a[m+1]='-';
    int mx=0,id=0;
    for(int i=1;i<=m;i+=2)
    {
        if(mx>i)
            p[i]=std::min(p[2*id-i],mx-i);
        else
            p[i]=1;
        while(a[i+p[i]]-'0'+a[i-p[i]]-'0'==1||(a[i+p[i]]==a[i-p[i]]&&a[i+p[i]]=='#'))
            ++p[i];
        if(i+p[i]>mx)
            mx=i+p[i],id=i;
    }
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n);
    scanf("%s",s+1);
    manacher();
    ll ans=0;
    for(int i=1;i<=m;i+=2)
        ans+=(p[i]-1)/2;
    printf("%lld\n",ans);
    return 0;
}

回文自动机

因为我新学了PAM,所以这篇博客更新了。

根本上来说只要把==改成!=即可,但是这样一来很多停止条件就没了,需要很多特判手动刹车,最后统计一下size即可

但是!=是一个很弱的条件,改成相加为1更好。

要去掉长度为奇数的回文串。方法是如果跳 p 跳到 1 了,直接 last=0;return;`即可。

#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
    T x=0,w=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*w;
}
template<class T> T read(T&x){
    return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;

co int N=500000+10;
char s[N];
int last=1,tot=1;
int ch[N][26],fa[N]={1,1},len[N]={0,-1},siz[N];

int get_fa(int x,int i){
    while(x!=1&&s[i-len[x]-1]-'0'+s[i]-'0'!=1) x=fa[x];
    return x;
}
void extend(int i){
    int p=get_fa(last,i);
    if(p==1) {last=0;return;}
    int x=ch[p][s[i]-'0'];
    if(!x){
        x=++tot;
        int q=get_fa(fa[p],i);
        if(q==1) fa[x]=0;
        else fa[x]=ch[q][s[i]-'0'];
        len[x]=len[p]+2;
        ch[p][s[i]-'0']=x;
    }
    ++siz[x];
    last=x;
}
int main(){
    int n=read<int>();
    scanf("%s",s+1);
    for(int i=1;i<=n;++i) extend(i);
    int ans=0;
    for(int i=tot;i>=2;--i){
        ans+=siz[i];
        siz[fa[i]]+=siz[i];
    }
    printf("%d\n",ans);
    return 0;
}

Poi2010 Antisymmetry

标签:names   def   去掉   ace   temp   sdi   amp   %s   就是   

原文地址:https://www.cnblogs.com/autoint/p/10327257.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!