1. 程式人生 > >計蒜客 2018南京網路賽 I Skr(馬拉車+雜湊)

計蒜客 2018南京網路賽 I Skr(馬拉車+雜湊)

題目:給一串由0..9組成的數字字串,求所有不同迴文串的權值和。比如說“1121”這個串中有“1”,“2”,“11”,“121”三種迴文串,他們的權值分別是1,2,11,121。最終輸出ans=135

思路:昨天比賽時讀題給讀錯了樣例也沒看怎麼來的。寫成了所有的迴文串權值和。。。碼完程式碼發現,瑪德樣例都不對,再讀了一遍題,真是智障啊。

今天看到有大佬討論馬拉車+雜湊的做法,(本菜雞學的馬拉車都擱淺了一年多了),就重新看了看kungbin的模板,寫了一下。瞭解馬拉車原理會發現它對這個題本身就有個剪枝(i 這個字串往外擴的初始長度Mp[i]直接就是剪掉了1..Mp[i]長度之後的啦)。但是仍然會有重複的(我map去重T了),這裡再去重的辦法就很巧妙了%%%,然後具體算權值時hash預處理,然後O(1)查詢就好

先貼一個manacher的模板

///求最長迴文子串
const int MAXN=110010;
char Ma[MAXN*2];
int Mp[MAXN*2];
void Manacher(char s[],int len)
{
    int l=0;
    Ma[l++]='$';
    Ma[l++]='#';
    for(int i=0;i<len;i++)
    {
        Ma[l++]=s[i];
        Ma[l++]='#';
    }
    Ma[l]=0;

    int mx=0,id=0;
    for(int i=0;i<l;i++)
    {
        Mp[i]=mx>i?min(Mp[2*id−i],mx−i):1;
        while(Ma[i+Mp[i]]==Ma[i−Mp[i]])
            Mp[i]++;
        if(i+Mp[i]>mx)
        {
            mx=i+Mp[i];
            id=i;
        }
    }
}
/*
* abaaba
* i: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
* Ma[i]: $ # a # b # a # a # b # a #
* Mp[i]: 1 1 2 1 4 1 2 7 2 1 4 1 2 1
*/
char s[MAXN];
int main()
{
    while(scanf("%s",s)==1)
    {
        int len=strlen(s);
        Manacher(s,len);
        int ans=0;
        for(int i=0;i<2*len+2;i++)
            ans=max(ans,Mp[i]−1);
        printf("%d\n",ans);
    }
    return 0;
}

這個題的程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=2000000+10;
const ll mod=1e9+7;
const ull bas=100007;
ull p[maxn<<1],has[maxn<<1];
ll pw[maxn<<1],sum[maxn<<1];

const int MOD=4000007;
int first[maxn<<1],nxt[maxn<<1],cnt=0;
ull val[maxn<<1];
bool exist(ull now)
{
       int u=now%MOD;
       for(int i=first[u];i;i=nxt[i])
           if(val[i]==now) return true;
       nxt[++cnt]=first[u];
       first[u]=cnt;
       val[cnt]=now;
       return false;
}
ull gethas(int l,int r)
{
    return has[r]-has[l-1]*p[r-l+1];
}
ll solve(int l,int r)
{
    ull tmp=gethas(l,r);
    if(exist(tmp)) return 0;
    ll ans=sum[r]-sum[l-1]*pw[(r-l+1+1)/2]%mod+mod;
    if(ans>mod)
        ans%=mod;
    return ans;
}
char Ma[maxn<<1];
int Mp[maxn<<1];
ll Manacher(char s[],int len)
{
    int l=0;
    Ma[l++]='$';
    Ma[l++]='#';
    for(int i=0;i<len;i++)
    {
        Ma[l++]=s[i];
        Ma[l++]='#';
    }
    Ma[l]=0;

    pw[0]=p[0]=1;
    has[0]=sum[0]=0;
    for(int i=1;i<=l;i++)
    {
        p[i]=p[i-1]*bas;
        has[i]=has[i-1]*bas+Ma[i];
        pw[i]=pw[i-1]*10%mod;
        if(Ma[i]>='0'&&Ma[i]<='9')
            sum[i]=(sum[i-1]*10+Ma[i]-'0')%mod;
        else
            sum[i]=sum[i-1];
    }

    ll ans=0;
    int mx=0,id=0;
    for(int i=0;i<l;i++)
    {
        if(Ma[i]!='#')
            ans=(ans+solve(i,i))%mod;
        Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
        while(Ma[i+Mp[i]]==Ma[i-Mp[i]])
        {
            if(Ma[i+Mp[i]]!='#')
                ans=(ans+solve(i-Mp[i],i+Mp[i]))%mod;
            Mp[i]++;
        }
        if(i+Mp[i]>mx)
        {
            mx=i+Mp[i];
            id=i;
        }
    }
    return ans;
}
char s[maxn];
int main()
{
    scanf("%s",s);
    int len=strlen(s);
    printf("%lld\n",Manacher(s,len));
    return 0;
}