【BZOJ2084】【洛谷P3501】[POI2010]ANT-Antisymmetry(Manache算法)
阿新 • • 發佈:2018-07-14
異或操作 image font bzoj rdquo 技術 sign ant close
題意描述
原題:
一句話描述:對於一個0/1序列,求出其中異或意義下回文的子串數量。
題解
我們可以看出,這個其實是一個對於異或意義下的回文子串數量的統計,什麽是異或意義下呢?平常,我們對回文的定義是,對於任意$i$,$S[i]=S[n-i+1]$,而我們把相等改為異或操作,那麽,當且僅當$1$與$0$相匹配時,返回值為$1$ 也就是 “真”。
那麽,我們可以嘗試使用Manache算法來解決。當然,編程時,我們並不必真的去把0/1序列轉換為數字序列,進行異或操作,這樣會給自己增加一波常數(迷),我們構造一個to數組,$to[x]$數組的定義為 對於字符$x$ 我們允許匹配的對應字符,顯然,$to[‘0‘]=‘1‘$,$to[‘1‘]=‘0‘$,特別的$ to[‘\#‘]=‘\#‘ $ $to[‘\$‘]=‘\$‘ $。(此處‘#‘與‘$‘是Manache算法的分隔字符與防止溢出字符,可以自定義)。
對於代碼:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 const int maxn = 1000010; 5 typedef unsigned long long ull; 6 char SS1[maxn],S[maxn],to[500]; 7 int n,len[maxn],tot=1; 8 int main() { 9 scanf("%d%s",&n,SS1+1);S[0]=‘$‘,S[1]=‘#‘; 10 forView Code(register int i=1;i<=n;++i) S[++tot]=SS1[i],S[++tot]=‘#‘; 11 to[‘1‘]=‘0‘,to[‘0‘]=‘1‘,to[‘#‘]=‘#‘,to[‘$‘]=‘$‘; 12 int pos=1,mx=1;ull ans=0; 13 for(register int i=1;i<=tot;i+=2) { 14 len[i]=(i<mx?std::min(mx-i,len[(pos<<1)-i]):1); 15 while(S[i+len[i]]==to[S[i-len[i]]]) len[i]++;16 if(len[i]+i>mx) { 17 mx=len[i]+i;pos=i; 18 } 19 ans+=len[i]>>1; 20 } 21 printf("%llu\n",ans); 22 return 0; 23 }
【BZOJ2084】【洛谷P3501】[POI2010]ANT-Antisymmetry(Manache算法)