2.7 2.8
放寒假了啊~
题解写起来比较麻烦,遂只记录一些算法和 trick。
目前文章格式已经被洛谷题解规范重塑过了
一
用 Trie 存一些数字的二进制,通过交换左右子树的方式,我们可以维护:
1.所有数字+1,2.求所有数字的异或值(当然在能 Trie 上维护的信息均可)
二
ACAM,SA,SAM,后缀排序,后缀排序求 height 数组(神奇性质)
放一些板板
ACAM
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=2e5+5,maxm=2e6+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
int n;
char c[maxm];
struct node{
int s[26],fail,ans,in;
};
node t[maxn];
int ans[maxn];
int tot=1;
int insert(){
int s=strlen(c);
int p=1;
for(int i=0;i<s;i++){
if(!t[p].s[c[i]-'a']) t[p].s[c[i]-'a']=++tot;
p=t[p].s[c[i]-'a'];
}
return p;
}
void build(){
for(int i=0;i<26;i++) t[0].s[i]=1;
queue<int> q;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
if(t[u].s[i]){
t[t[u].s[i]].fail=t[t[u].fail].s[i];
++t[t[t[u].fail].s[i]].in;
q.push(t[u].s[i]);
}
else t[u].s[i]=t[t[u].fail].s[i];
}
}
}
void query(){
int p=1,s=strlen(c);
for(int i=0;i<s;i++){
p=t[p].s[c[i]-'a'];
++t[p].ans;
}
}
void topo(){
queue<int> st;
for(int i=0;i<=tot;i++){
if(!t[i].in) st.push(i);
}
while(!st.empty()){
int u=st.front();
st.pop();
int v=t[u].fail;
--t[v].in,t[v].ans+=t[u].ans;
if(!t[v].in) st.push(v);
}
}
int que[maxn];
int main(){
read(n);
for(int i=1;i<=n;i++){
scanf("%s",c);
que[i]=insert();
}
build();
scanf("%s",c);
query(); topo();
for(int i=1;i<=n;i++){
printf("%d\n",t[que[i]].ans);
}
return 0;
}
//^o^
SAM(也可用于求 SA)
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=2e6+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
struct node{
int s[26],len,fa;
}t[maxn<<1];
int las=1,tot=1;
void add(int c){
int p=las,np=las=++tot;
t[np].len=t[p].len+1;
for(;p&&(!t[p].s[c]);p=t[p].fa) t[p].s[c]=np;
if(!p) t[np].fa=1;
else{
int q=t[p].s[c];
if(t[q].len==t[p].len+1) t[np].fa=q;
else{
int nq=++tot;
t[nq]=t[q],t[nq].len=t[p].len+1;
t[np].fa=t[q].fa=nq;
for(;p&&t[p].s[c]==q;p=t[p].fa) t[p].s[c]=nq;
}
}
}
bool check(string& s){
int p=1;
for(int i=0;i<(int)s.size();i++){
if(!t[p].s[s[i]-'a']) return false;
p=t[p].s[s[i]-'a'];
}
return true;
}
string s;
int main(){
cin>>s;
for(int i=0;i<(int)s.size();i++){
add(s[i]-'a');
}
while(true){
cin>>s;
if(check(s)) cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
return 0;
}
//^o^
后缀排序及 height
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=2e6+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
int rk[maxn],rki[maxn],sa[maxn],cnt[maxn],id[maxn],h[maxn];
void getSa(string s){
int n=s.size(),m=150,p=0;
for(int i=0;i<n;i++) ++cnt[rk[i+1]=s[i]];
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
for(int w=1;w<=n;w<<=1,m=p){
int cur=0;
for(int i=n-w+1;i<=n;i++) id[++cur]=i;
for(int i=n;i>=1;i--){
if(sa[i]>w) id[++cur]=sa[i]-w;
}
fill(cnt,cnt+m+2,0);
for(int i=1;i<=n;i++) ++cnt[rk[i]];
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[id[i]]]--]=id[i];
copy(rk+1,rk+n+1,rki+1);
p=0;
for(int i=1;i<=n;i++){
if(rki[sa[i]]==rki[sa[i-1]]&&rki[sa[i]+w]==rki[sa[i-1]+w]){
rk[sa[i]]=p;
}
else{
rk[sa[i]]=++p;
}
}
if(p==n) break;
}
int k=0;
for(int i=1;i<=n;i++){
if(rk[i]==1) continue;
if(k) --k;
while(i-1+k<n&&s[i-1+k]==s[sa[rk[i]-1]-1+k]) ++k;
h[rk[i]]=k;
}
for(int i=1;i<=n;i++) cout<<sa[i]<<' ';
cout<<endl;
for(int i=1;i<=n;i++) cout<<h[i]<<' ';
cout<<endl;
}
int main(){
string s; cin>>s;
getSa(s);
return 0;
}
//^o^
三
今日 ARC 又遇见拆位,总之看见位运算拆拆位总是没错的。
2.23 补充一下,看到异或还要想到 Trie 树!

浙公网安备 33010602011771号