bzoj2084/luoguP3501 [Cerc2014]Virus synthesis(回文自动机)
作者:互联网
对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。
题解时间
这玩意咋看都像是回文串不是嘛。
然后与此同时还是经典计数问题。
所以考虑能不能以这里面的这个规则写个PAM
发现还真能搞:
首先这种串只有偶串,所以不建奇方向的(跳到奇根1直接跳出)
此外再把match改一下
完事了。
#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
namespace RKK
{
const int N=500011;
char str[N];int n;
struct remilia{int tranc[2],len,fail;};
struct sakuya
{
remilia p[N];
int fin,size;
int val[N];
sakuya()
{
fin=0,size=1;
p[0].len=0,p[1].len=-1;
p[0].fail=p[1].fail=1;
}
int match(char *s,int i,int px){return p[px].len==-1||(i-p[px].len-1!=0&&s[i-p[px].len-1]!=s[i]);}
void ins(char *s,int i)
{
int ch=s[i]-'0';
int npx,lpx,lpy;
lpx=fin;
while(!match(s,i,lpx)) lpx=p[lpx].fail;
if(i-p[lpx].len-1==0||s[i-p[lpx].len-1]==s[i]){fin=0;return;}
if(!p[lpx].tranc[ch])
{
npx=++size;
p[npx].len=p[lpx].len+2;
lpy=p[lpx].fail;
while(!match(s,i,lpy)) lpy=p[lpy].fail;
p[npx].fail=p[lpy].tranc[ch];
p[lpx].tranc[ch]=npx;
}
fin=p[lpx].tranc[ch];
val[fin]++;
}
void work()
{
lint ans=0;
for(int i=size;i>=2;i--) val[p[i].fail]+=val[i],ans+=val[i];
printf("%lld\n",ans);
}
}pam;
int Iris()
{
scanf("%d%s",&n,str+1);
for(int i=1;i<=n;i++) pam.ins(str,i);
pam.work();
return 0;
}
}
int main(){return RKK::Iris();}
标签:bzoj2084,lpy,lpx,int,len,Virus,luoguP3501,fail,fin 来源: https://www.cnblogs.com/rikurika/p/12079220.html