zoukankan      html  css  js  c++  java
  • manacher

    https://winniechen.cn/?p=208 可能这里的更好看一点?

    manacher算法

    理论上,我觉得这个算法应该是算作DP的一种,这是我的写法,还请不要嘲笑,毕竟这玩意是我自己YY出来的...

    manacher算法,用来求最大每个回文中心的最大回文半径...这个东西,我们发现可以通过DP来实现...

    我们考虑,维护一个now满足在现在[1,i-1]中now+f[now] ge f[1...i-1]+1...i-1,现在我们就可以得到一个目前可以的最靠后的回文串...之后针对i 满足f[i]=min(f[(now<<1)-i],f[now]+now-i)也就是求一个已知串中最长的一个回文串,之后在向两侧拓展即可...

    时间复杂度的证明:因为最多会拓展n次,所以时间复杂度为O(n)的...

    另外,值得注意的是,如果求的回文串长度可以为偶数,就需要在原串的空白位置加上一个特殊字符...比如说#什么的...

    例题时间

    BZOJ 2565: 最长双回文串

    题目很显然,是找到一个#的左侧回文串长度+右侧回文串长度最大...

    那么我们可以发现,在维护f[i]数组的同时,维护一个l[i],r[i]的差分表示以i的左右边界的最长回文串...

    最后差分一下,l[i]=max(l[i+1]-1,l[i]);之后统计答案...

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    #define N 200005
    char s[N],str[N];
    int n,m,g[N],h[N],f[N],ans=2;
    int main()
    {
    	scanf("%s",s+1);n=strlen(s+1);memset(g,0x3f,sizeof(g));
    	for(int i=1;i<=n;i++)str[++m]='#',str[++m]=s[i];str[++m]='#';f[1]=0;
    	for(int i=1,now=1;i<=m;i++)
    	{
    		f[i]=min(f[(now<<1)-i],f[now]+now-i);
    		for(;i-f[i]-1>0&&i+f[i]+1<=m;)
    		{
    			if(str[i-f[i]-1]!=str[i+f[i]+1])break;
    			f[i]++;
    		}//printf("%d
    ",f[i]);
    		if(f[i]+i>f[now]+now)now=i;
    		g[i+f[i]]=min(g[i+f[i]],i-f[i]);
    		h[i-f[i]]=max(h[i-f[i]],i+f[i]);
    	}
    	for(int i=1;i<=m;i++)h[i]=max(h[i-1]-1,h[i]);
    	for(int i=m;i;i--)g[i]=min(g[i],g[i+1]+1);
    	for(int i=1;i<=m;i++)if(str[i]=='#')ans=max(ans,(h[i]-g[i]+1)>>1);
    	printf("%d
    ",ans);return 0;
    }

    BZOJ 3790: 神奇项链

    题目很有问题,但是我最后理解了...求用最少的回文串拼接成原串...

    我们把每个$i$为回文中心的回文串拿出来,之后贪心的求一下最小区间覆盖即可。

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    #define N 200005
    char s[N],str[N];
    int n,m,f[N],ans=2;
    // void fix(int x,int v){for(;x;x-=x&-x)minn[x]=min(minn[x],v);}
    // int find(int x){int ret=1<<30;for(;x<N;x+=x&-x)ret=min(minn[x],ret);return ret;}
    struct node{int l,r;}a[N];
    bool cmp(const node &a,const node &b){return a.l==b.l?a.r>b.r:a.l<b.l;}
    int main()
    {
        while(scanf("%s",s+1)!=EOF)
        {
            n=strlen(s+1);m=0;
            for(int i=1;i<=n;i++)str[++m]='#',str[++m]=s[i];str[++m]='#';f[1]=0;
            for(int i=1,now=1;i<=m;i++)
            {
                f[i]=min(f[(now<<1)-i],f[now]+now-i);
                for(;i-f[i]-1>0&&i+f[i]+1<=m;)
                {
                    if(str[i-f[i]-1]!=str[i+f[i]+1])break;
                    f[i]++;
                }//printf("%d
    ",f[i]);
                if(f[i]+i>f[now]+now)now=i;
                a[i].l=(i-f[i]+1)>>1,a[i].r=(i+f[i])>>1;
                // printf("%d %d %d %d
    ",a[i].l,a[i].r,i,f[i]);
            }sort(a+1,a+m+1,cmp);int mx=0,ans=0;
            for(int i=1;mx<n;ans++)
            {
                int tmp=0;
                while(i<=m&&a[i].l<=mx+1)tmp=max(tmp,a[i++].r);mx=tmp;
            }printf("%d
    ",ans-1);
        }return 0;
    }

    BZOJ 2160: 拉拉队排练

    题目大意:求出所有的奇数长度的回文串,之后取前K个即可...

    我们发现,我们只需要把每个点作为回文中心的最长回文半径求出来,之后差分一下,求一个前缀和...最后一个快速幂即可...

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    #define N 1000005
    #define ll long long
    #define mod 19930726
    char buf[1000005],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000005,stdin),p1==p2)?EOF:*p1++)
    char s[N];ll K;
    int n,m,f[N],ans=2,c[N],d[N];
    __attribute__((optimize("-O3")))inline void gc() {
    	register int x=0;register char c;while(c<'a'||c>'z')c=nc();
    	while(c<='z'&&c>='a')s[++x]=c,c=nc();
    }
    __attribute__((optimize("-O3")))ll q_pow(ll x,int n){ll ret=1;for(;n;n>>=1,x=x*x%mod)if(n&1)ret=ret*x%mod;return ret;}
    __attribute__((optimize("-O3")))int main()
    {
    	scanf("%d%lld",&n,&K);gc();
    	f[1]=0;
    	for(int i=1,now=1;i<=n;i++)
    	{
    		f[i]=min(f[(now<<1)-i],f[now]+now-i);
    		for(;;)
    		{
    			if(s[i-f[i]-1]!=s[i+f[i]+1])break;
    			f[i]++;
    		}//printf("%d
    ",f[i]);
    		if(f[i]+i>f[now]+now)now=i;
    	}
    	for(int i=1;i<=n;i++)c[f[i]+1]--,c[0]++;ll sum=c[0];
    	for(int i=1;i<=n;i++)c[i]+=c[i-1],sum+=c[i];if(sum<K){puts("-1");return 0;}ll ans=1;
    	for(int i=n;~i;i--)
    	{
    		if(c[i]>=K)
    		{
    			printf("%lld
    ",ans*q_pow((i<<1)+1,K)%mod);
    			return 0;
    		}K-=c[i];ans=ans*q_pow((i<<1)+1,c[i])%mod;
    		// printf("%d
    ",c[i]);
    	}
    }
    

      

  • 相关阅读:
    Debian如何永久添加静态路由
    一句话换个说法的软件
    高级程序员简历,技术总监喜欢什么简历?
    CP936实际上是GBK,编码问题再次让我熬夜
    句子说法转换的软件,基于AI技术
    输入关键词自动生成文章(2020年人工智能写作)
    自动写文章的智能软件(基于AI写作)
    python调用接口,python接收post请求接口(附完整代码)
    人工智能是铁饭碗还是铁坑,看看人工智能博士怎么说
    远离外包公司,就是远离码农的血汗工厂
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9525846.html
Copyright © 2011-2022 走看看