manacher算法解题

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了manacher算法解题相关的知识,希望对你有一定的参考价值。

P1659 [国家集训队]拉拉队排练
1.思维误区:长度为5的最大回文串一定也是长度为3的回文串!!
2.快速幂,和取模这样的技巧处理不好,会很容易wa,并且还不知道自己错在哪。
3. ans[p[i]-1]++; 回文串的长度统计.由于区间的对称性,和算法对于回文串的特殊处理,p[i]-1就是该字符在原串中的回文长度。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e6+5;
const int mod=19930726;
string s;
int p[maxn],n,k,ans[maxn],g;
bool cmp(int x,int y)

    return x>y;

int fastpow(int x,int y)

    int tmp=1;
    while(y)
        if(y&1)
            tmp*=x,tmp%=mod;
        x*=x,x%=mod;
        y>>=1;
    
    return tmp;

void manacher()

    string ss="@#";
    for(int i=0;i<s.length();i++)
        ss+=s[i],ss+='#';
    int len=ss.length();
    int mx=0; //当前延伸最远的回文子串,下标的后一位
    int id=0; //对称中心
    for (int i=1;i<len;i++)
    
        if(i<mx)  p[i]=min(p[2*id-i],mx-i);
        else
            p[i]=1;
        while(ss[i+p[i]]==ss[i-p[i]]) 
            p[i]++;
        if(p[i]+i>mx)
            mx=p[i]+i,id=i;
        if((p[i]-1)%2)
            ans[p[i]-1]++;  //回文串的长度统计
    


signed main()

    cin>>n>>k>>s;
    manacher();
    int tmp=1,sum=0;
    for(int i=n;i>=1;i--)
    
        if(i%2==0) continue;
        sum+=ans[i];
        if(k>=sum)
        
            tmp*=fastpow(i,sum);
            tmp%=mod,k-=sum;
        
        else
        
            tmp*=fastpow(i,k),tmp%=mod;
            k-=sum;break;
        
    
    if(k>0)
        cout<<-1<<endl;
    cout<<tmp<<endl;
    return 0;


P4555 [国家集训队]最长双回文串

https://www.luogu.com.cn/blog/111990/solution-p4555

#include <bits/stdc++.h>
//#define int long long
using namespace std;
const int maxn=5e6+5;
const int mod=19930726;
int p[maxn],l[maxn],r[maxn];
string s1,s2;
void manacher()

    s2="@#";
    for(int i=0;i<s1.length();i++)
        s2+=s1[i],s2+='#';
    int mx=0,id=0,len=s2.length();
    for(int i=1;i<len;i++)
    
        if(i<mx)
            p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(s2[i+p[i]]==s2[i-p[i]]) p[i]++;
        if(i+p[i]>mx)
            mx=i+p[i],id=i;
        l[i-p[i]+1]=max(l[i-p[i]+1],p[i]-1);
        //以i为开头的最长回文字符串
        r[i+p[i]-1]=max(r[i+p[i]-1],p[i]-1);
        //以i为结尾的最长回文字符串
    
    for(int i=3;i<=len;i+=2) l[i]=max(l[i],l[i-2]-2);
    for(int i=len-2;i>=3;i-=2) r[i]=max(r[i],r[i+2]-2);
    int ans=0;
    for(int i=3;i<=len;i+=2)
        if(l[i]&&r[i])
            ans=max(ans,l[i]+r[i]);
    cout<<ans<<endl;


signed main()

    cin>>s1;
    manacher();

    return 0;


C. Madoka and Childish Pranks

思维题:map和pair的记录点方式。本题将要标记的点染黑,若是从前往后染色,存在覆盖的问题;从后往前染,则不存在。本题并不求最小次数,用12或21操作。

#include <bits/stdc++.h>
//#define int long long
using namespace std;
const int maxn=5e6+5;
const int mod=19930726;
char ch[105][105];
int n,m;
signed main()

    int t;cin>>t;
    while(t--)
    
        map<pair<int,int>,pair<int,int> >mp;
        mp.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            cin>>ch[i][j];
        if(ch[1][1]=='1')
        
            cout<<"-1"<<endl;continue;
        
        int ans=0;
        for(int i=n;i>=1;i--)
        
            for(int j=m;j>=1;j--)
            
                if(ch[i][j]=='1')
                
                    if(i!=1)
                        mp[i,j]=i-1,j;
                    else
                        mp[i,j]=i,j-1;
                    ans++;
                
            
        
        cout<<ans<<endl;
        for(int i=n;i>=1;i--)
            for(int j=m;j>=1;j--)
            if(ch[i][j]=='1')
            
cout<<mp[i,j].first<<" "<<mp[i,j].second<<" "<<i<<" "<<j<<endl;
            
    
    return 0;

以上是关于manacher算法解题的主要内容,如果未能解决你的问题,请参考以下文章

HDU 3613 Best Reward Manacher算法

集训第三天·疯狂训练哦,顺带学习了manacher

备战省选

P4555 [国家集训队]最长双回文串

[国家集训队]最长双回文串

正睿2018暑假集训 比赛题选做