題面
給定兩個字符串 \(a,b\),要求出兩個數組:\(b\) 的 \(z\) 函數數組 \(z\)、\(b\) 與 \(a\) 的每一個后綴的
LCP
長度數組 \(p\)。
數據范圍:\(1\le |a|,|b|\le 2\times 10^7\)。
蒟蒻語
別的題解為什么代碼那么長、講解那么復雜?蒟蒻不解,寫篇易懂一點的,希望沒有錯誤理解。
注意:蒟蒻的下標是從 \(0\) 開始的。
蒟蒻解
定義 \(z(i) (i>0)\):后綴 \(i\) 與字符串的 LCP
長度,勸退一點地說:
\[z(i)=\max_{len=1}^{|s|-i} \left(len\cdot [\forall 0\le x<len,s[(0)+(x)]=s[(i)+(x)]]\right) \]
對於求字符串 \(s\) 的 \(z\) 函數,可以用遞推解決一部分問題,蒟蒻先放上精美的代碼:
這里特定 \(z(0)=0\)(題目中 \(z(0)=|s|\))。
void getz(string s){
int l=0;
R(i,1,sz(s)){
if(l+z[l]>i) z[i]=min(z[i-l],l+z[l]-i);
while(i+z[i]<sz(s)&&s[z[i]]==s[i+z[i]]) z[i]++;
if(i+z[i]>l+z[l]) l=i;
}
// R(i,0,sz(s)) cout<<z[i]<<" ";cout<<'\n';
}
結論: 對於 \(i>0\),對任意 \(0\le l<i\) 都可以遞推得:
\[\forall 0\le x<\min(z(i-l),l+z(l)-i),s[(i)+(x)]=s[(0)+(x)] \]
證明:
\[\begin{aligned} &s[(i)+(x)]\\ =&s[(l)+(i+x-l)]\\ =&s[(0)+(i+x-l)]\color{red}{(x\le l+z(l)-i)}\\ =&s[(i-l)+(x)]\\ =&s[(0)+(x)]\color{red}{(x\le z(i-l))}\\ \end{aligned} \]
所以可以選定某個 \(0\le l<i\),初始化 \(z(i)=\min(z(i-l),l+z(l)-i)\),然后暴力判斷字符相等增加 \(z(i)\)。
這里 \(l\) 選滿足 \(j+z(j)(0\le j<i)\) 最大的 \(j\),這樣每個字符只會被暴力判斷一次,所以時間復雜度可以做到 \(\Theta(n)\)。
對於題目中的問題其實把 \(b\) 和 \(a\) 接起來做個 \(z\) 就可以了。
代碼
#include <bits/stdc++.h>
using namespace std;
//Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair((a),(b))
#define x first
#define y second
#define Be begin()
#define En end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
#define R(i,a,b) for(int i=(a),I=(b);i<I;i++)
#define L(i,a,b) for(int i=(b)-1,I=(a)-1;i>I;i--)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
//Data
const int N=2e7;
ll ansz,ansp;
string a,b;
//Zfunction
int z[N<<1];
void getz(string s){
int l=0;
R(i,1,sz(s)){
if(l+z[l]>i) z[i]=min(z[i-l],l+z[l]-i);
while(i+z[i]<sz(s)&&s[z[i]]==s[i+z[i]]) z[i]++;
if(i+z[i]>l+z[l]) l=i;
}
// R(i,0,sz(s)) cout<<z[i]<<" ";cout<<'\n';
}
//Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>a>>b,getz(b+a);
ansz^=1ll*(sz(b)+1)*(0+1);
R(i,1,sz(b)) ansz^=1ll*(min(z[i],sz(b)-i)+1)*(i+1);
R(i,0,sz(a)) ansp^=1ll*(min(z[i+sz(b)],sz(b))+1)*(i+1);
cout<<ansz<<'\n'<<ansp<<'\n';
return 0;
}
祝大家學習愉快!