洛谷題目傳送門html
神仙思惟題。c++
對於兩個字符串的匹配問題,彷佛以前蒟蒻寫的HAOI2010最長公共子序列題解中提到的建網格圖模型是一種套路?spa
給一個稍微強一點的樣例(把字母換成了ABC)code
AABCB BACBA
它所對應的網格圖以下(橫軸表明\(s\),縱軸表明\(t\),顯示的點表示可達狀態)htm
咱們首先能夠大體肯定,全部的可達狀態在一個不規則圖形的界內
(紅色線條)。第\(i\)行(或列)的界是\([l_i,r_i]\),並且相似two pointers,\(l_i\)和\(r_i\)都隨\(i\)單調不降。拐角的頂點\((x,y)\)出如今前綴\(s_x\)和前綴\(t_y\)第一次匹配到其中一個是另外一個的子序列的地方。blog
那麼是否是這個界裏面的狀態均可達呢?顯然不是,咱們還能夠看到這樣的位置(中間有三個):若是\(s_x=t_{y-1}\neq s_{x-1}=t_y\)的話,\((x,y)\)也會不可達。對應的兩個子串形如AB
和BA
,蒟蒻接下來把該狀態記做AB-BA。字符串
仔細觀察一下(或者打個表),除了這種狀況,還有沒有別的狀況也是在界內卻不可達的?貌似找不到啊。。。。。。get
實際上,咱們大概能夠證實,在這個界內有且僅有AB-BA狀態不可達。flash
圖中的若干有向邊從前驅節點指向後繼節點。顯然若是一個狀態不可達,那麼要麼它沒有前驅,要麼它的全部前驅都不可達。it
首先,一個節點沒有前驅的狀況就只有AB-BA那一種。當\(s_x=t_y\)時,咱們能夠確定\((x,y)\)有前驅,隨手畫畫就能夠發現。
因而如今咱們就須要證實,若是一個點不可達,那麼它必定沒有前驅,而不會出現它有前驅且前驅不可達。反證法,咱們如今開始斷定一個在界內的有前驅的節點\((x,y)\),並假設它和它的前驅都不可達。
因而,咱們若是要假設某個點的全部前驅都不可達,咱們必須假設它的某一個前驅的全部前驅都不可達,接着是前驅的前驅的前驅。。。。。。這個過程當中\(x,y\)在遞減,而最終\((x,y)\)到了邊界上。顯然邊界上的點都是可達狀態(從\((0,0)\)出發造成一條輪廓狀路徑),因而全部的假設都被推翻了。
思路清晰了之後,代碼就簡單了,只須要注意些細節。動態匹配子序列,維護\(l,r\),還有對不一樣的狀態記前綴和,這些都沒什麼好說的了。
#include<bits/stdc++.h> #define RG register #define R RG int using namespace std; const int N=1e6+9; char s[N],t[N]; int f[N][8]; int main(){ R n=0,m=0,x,y,l=0,r=0; RG long long ans=0; scanf("%s%s",s,t); for(n=0;s[n];++n)s[n]%=3;//只是湊巧發現RBG%3的餘數不同 for(m=0;t[m];++m)t[m]%=3; for(x=1;x<n;++x){ memcpy(f[x],f[x-1],32);//前綴和 if(s[x-1]!=s[x]) ++f[x][(s[x-1]>s[x])*4+s[x-1]+s[x]]; } memcpy(f[n],f[n-1],32); for(y=0;y<m;++y){ if(y&&t[y-1]!=t[y]){//注意邊界 x=(t[y-1]<t[y])*4+t[y-1]+t[y]; ans-=f[r][x]-f[l][x]; } while(r<n&&s[r]!=t[y])++r; ans+=r-l+1-(r==n);//一樣注意邊界 if(r<n)++r; if(l<r&&s[l]==t[y])++l; } cout<<ans<<endl; return 0; }