zoukankan      html  css  js  c++  java
  • bzoj2084/luoguP3501 [Poi2010]Antisymmetry(回文自动机+dp)

    bzoj2084/luoguP3501 [Poi2010]Antisymmetry(回文自动机+dp)

    bzoj Luogu

    对于一个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
    ",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();}
    
  • 相关阅读:
    写一个含数字,拼音,汉字的验证码生成类
    Vue.js 学习示例
    webapi
    webapi
    WebApi接口
    WebApi接口
    WebApi
    个人插件锦集
    ShenNiu.MVC管理系统
    Centos6搭建Samba服务并使用Windows挂载
  • 原文地址:https://www.cnblogs.com/rikurika/p/12079220.html
Copyright © 2011-2022 走看看