計蒜客 2018南京網路賽 I Skr(馬拉車+雜湊)
阿新 • • 發佈:2019-02-11
題目:給一串由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; }