zoukankan      html  css  js  c++  java
  • [BZOJ3790] 神奇项链

    想要成为我的master嘛?

    题目大意:用最少的回文串覆盖整个字符串,可重叠。

    题解:Manacher+贪心

    md最近好几个线段覆盖的题都没看出来。

    Manacher算出以每个字符为中心的回文串,就是一个线段,计算出左端点i-Len[i]+1和

    右端点i+Len[i]-1,然后贪心用每个线段覆盖区间就好了,两个回文串,就是两个区间是

    可以重叠的。贪心嘛,就是以左端点为第一关键字,右端点为第二关键字排序。没次找

    能与上一条线段相接的右端点最大的就行了。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 50009
    using namespace std;
     
    char s[maxn*2],str[maxn*2];
    int len,Len[maxn*2];
    struct X{
        int l,r;
    }xd[maxn*2];
     
    bool cmp(X a,X b){
        if(a.l!=b.l)return a.l<b.l;
        else return a.r>b.r;
    }
     
    void getstr(){
        int k=0;str[k++]='$';
        for(int i=0;i<len;i++){
            str[k++]='#';str[k++]=s[i];
        }
        str[k++]='#';len=k;
    }
     
    void Manacher(){
        int mx=0,id;
        getstr();memset(Len,0,sizeof(Len));
        for(int i=1;i<len;i++){
            if(mx>i)Len[i]=min(Len[2*id-i],mx-i);
            else Len[i]=1;
            while(str[i+Len[i]]==str[i-Len[i]])Len[i]++;
            if(i+Len[i]>mx)mx=i+Len[i],id=i;
        }
    }
     
    int main(){
        while(scanf("%s",&s)!=EOF){
            len=strlen(s);
            Manacher();
            for(int i=1;i<len;i++){
                xd[i].l=i-Len[i]+1;xd[i].r=i+Len[i]-1;
            }
            sort(xd+1,xd+len,cmp);
            int ans=1,now=2,r=xd[1].r;
            while(r!=len-1){
                int mx=r;
                while(xd[now].l<=r&&now<len){
                    mx=max(mx,xd[now].r);now++;
                }
                r=mx;ans++;
            }
            cout<<ans-1<<endl;
        }
        return 0;
    }
  • 相关阅读:
    linux 网络编程比较好的文章
    linux 命令
    感冒了
    aa
    111
    仿京东(我的商城)鼠标上去弹出层效果
    仿汽车之家搜索页价格签区间(鼠标拖拽同时tip提示)
    关于DW 打不开后缀名为.ftl的文件 配置方法
    客户端与服务器段的交互 通过json
    jquery 阻止事件冒泡
  • 原文地址:https://www.cnblogs.com/zzyh/p/7679089.html
Copyright © 2011-2022 走看看