笔记-两道类似的 Z 函数习题
真是很神奇的东西,感觉有些题可以吊打 SAM
啊。
CF432D Prefixes and Suffixes
先对整个字符串搞一次 Z
。
如果 \(i+ze(i)=n\) 说明这是原串的一个 border
后缀,将 \(ze(i)\) 标为可能长度。
对每个 \(ze(i)\) 都 \(cnt(ze(i))++\),然后后缀和一下就好了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define x first
#define y second
#define bg begin()
#define ed end()
#define pb push_back
#define mp make_pair
#define sz(a) int((a).size())
#define R(i,n) for(int i(0);i<(n);++i)
#define L(i,n) for(int i((n)-1);i>=0;--i)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
//Data
const int N=1e5;
int n,cnt[N|1];
bool mat[N|1];
string str;
//Zebra
int ze[N];
void ze_init(){
int l=0;
R(i,n)if(i){
if(l+ze[l]>i) ze[i]=min(l+ze[l]-i,ze[i-l]);
while(i+ze[i]<n&&str[ze[i]]==str[i+ze[i]]) ze[i]++;
if(i+ze[i]>l+ze[l]) l=i;
}
}
//Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>str,n=sz(str),ze_init();
// R(i,n) cout<<ze[i]<<' '; cout<<'\n';
R(i,n)if(i){
if(i+ze[i]==n) mat[ze[i]]=true;
cnt[ze[i]]++;
}
mat[n]=true,cnt[n]++;
L(i,n) cnt[i]+=cnt[i+1];
int ns=0;
R(i,n+1) ns+=mat[i];
cout<<ns<<'\n';
R(i,n+1)if(mat[i]) cout<<i<<" "<<cnt[i]<<'\n';
return 0;
}
CF126B Password
同样标记可能的 border
后缀长度,然后对中间的 \(ze(i)\) 取个最大值。
找到小于等于最大值但是最大可能的下标即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define x first
#define y second
#define bg begin()
#define ed end()
#define pb push_back
#define mp make_pair
#define sz(a) int((a).size())
#define R(i,n) for(int i(0);i<(n);++i)
#define L(i,n) for(int i((n)-1);i>=0;--i)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
//Data
const int N=1e6;
int n;
bool mat[N];
string str;
//Zebra
int ze[N];
void ze_init(){
int l=0;
R(i,n)if(i){
if(l+ze[l]>i) ze[i]=min(l+ze[l]-i,ze[i-l]);
while(i+ze[i]<n&&str[ze[i]]==str[i+ze[i]]) ze[i]++;
if(i+ze[i]>l+ze[l]) l=i;
}
}
//Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>str,n=sz(str),ze_init();
// R(i,n) cout<<ze[i]<<' '; cout<<'\n';
int lcp=0,id=-1;
R(i,n)if(i){
if(i+ze[i]==n){
mat[ze[i]]=true;
if(ze[i]-1>lcp) lcp=ze[i]-1,id=i;
} else if(ze[i]>lcp) lcp=ze[i],id=i;
}
L(i,lcp+1)if(mat[i]){
for(int j=id;j<id+i;j++) cout<<str[j];
cout<<'\n',exit(0);
}
cout<<"Just a legend\n";
return 0;
}
\[\Huge\rm George1123\ is\ very\ no.
\]