首先:
jxrjxrjxr orz,沒有您我們都會死~
然後就是我從jxr神犇那裡借鑑(照抄)過來的字尾陣列模板。
#include#include#include#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
using namespace std;
const int n=100000+1000;
char s[n];
int a[n],b[n],c[n],sa[n],rk[n],h[n],n,*x,*y;
void radix(int m)
void getsa(int m)
}void geth()
真是十分的 短 啊~~~~~~
話說我現在才會字尾陣列真的好嗎,簡直違反基本法啊。
不過還是稀里糊塗地看懂(背下來)了。
於是就可以開心地去水題了。
沒錯其實我就是把09年那篇**裡面的題給水了下。
然後來寫下一句話題解。
poj1743:不可重疊最長重複子串
二分答案,height分組,維護最大最小sa,判定一下。
#include#include#include#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
using namespace std;
const int n=20000+5;
int s[n],a[n],b[n],c[n],sa[n],rk[n],h[n],n,*x,*y;
int abs(int x)
void radix(int m)
void getsa(int m)
}void geth()
bool check(int k)else
} return false;
}int main()
if(l>=5)printf("%d\n",l);
else puts("0");
} return 0;
}
spoj 694&705:本質不同的子串個數
sigma(n-sa[i]+1-height[i])
#include#include#include#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
using namespace std;
const int n=1000+5;
char s[n];
int sa[n],h[n],rk[n],a[n],b[n],c[n],*x,*y,n;
void radix(int m)
void getsa(int m)
}void geth()
int main()
return 0;
}
poj 3693:重複次數最多的連續重複子串(好繞啊)
列舉長度l,計算次數,複雜度是n*調和級數(n),中間細節比較麻煩。。。。。
#include#include#include#include#include#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
using namespace std;
const int n=100000+10;
struct suffix_array
void radix(int m)
void getsa(int m)
} void geth()
void rmq_init()
void pre()
}sol;
char s[n];
int a[n];
int main()else if(ti==ans)a[++top]=l;
} int len=-1,st;
for(int i=1;i<=n&&len==-1;i++)
for(int j=1;j<=top;j++)
} printf("case %d: ",++kase);
for(int i=st,j=1;j<=len*ans;j++,i++)putchar(s[i]);
putchar('\n');
} return 0;
}
poj 2774:雙串最長公共子串
兩個串中間加個奇怪的符號然後連線起來,跑一遍字尾陣列,當sa[i]和sa[i-1]不在乙個串時的最大height[i]即為答案。
#include#include#include#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
using namespace std;
const int n=200000+10;
char s[n];
int a[n],b[n],c[n],sa[n],rk[n],h[n],n,*x,*y;
void radix(int m)
void getsa(int m)
}void geth()
int main()
poj 3415:長度不小於k的公共子串個數
繼續串接,跑一遍字尾陣列,對於每乙個a的字尾和b的字尾計算一次lcp算出答案,於是n^2**,轉用單調棧維護a的height,掃到b的時候算一下,反過來再做一次,得出總答案。
#include#include#includeusing namespace std;
typedef long long ll;
#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
const int n=200000+5;
char s[n];
int a[n],b[n],c[n],sa[n],rk[n],h[n],n,*x,*y;
void radix(int m)
void getsa(int m)
}void geth()
int st[n][2];
int main()
} tot=top=0;
for(int i=2;i<=n+1;i++)
st[top][0]=h[i];st[top++][1]=cnt;
if(sa[i]
這題其實可以kmp做我會亂說= =+(常數我吃了)。
n個串連起來,中間有奇怪的不同的字元,跑一遍字尾陣列,二分答案,height分組,每組判定一下有木有集齊(7個字尾召喚神龍?)k個不在同乙個串的字尾,集齊了就可以(召喚神龍)return true
順便說這題召喚出了我人生中的第乙個ole(我也不造怎麼回事啊,然後莫名其妙就a了)
#include#include#includeusing namespace std;
#define cmp(x) (y[sa[i]+x]==y[sa[i-1]+x])
const int n=100000+1000;
char s[n];
int a[n],b[n],c[n],sa[n],rk[n],h[n],*x,*y,n;
void radix(int m)
void getsa(int m)
}void geth()
int in[n],t,k,now[105];
bool check(int len)
else
} }if(tot>k)return true;
return false;
}int ans[n];
void print(int len)
else
} }if(tot>k)ans[++sz]=sa[n];
ans[0]=sz;
}int main()
if(flag)puts("");
flag=true;
if(l==1)puts("?");
else
void getsa(int m)
}void geth()
int in[n],mx[15],mn[15],m;
bool check(int len)
} return false;
}int main()
else r=mid-1;
} printf("%d\n",ans);
} return 0;
}
然後其實還有乙個最小迴圈節和乙個最長回文串,其實這兩個用kmp和manacher做就好了嘛,還快一點呢。
總結一下嘛,這類題無非就是 串接,二分答案,height分組,偶爾再來個單調棧什麼的,其實做法都差不多,模型很相像,理解了height陣列和sa陣列的定義啊性質啊什麼的就很好做(水)了。
好了是時候開啟字尾自動機的大門了(還是好虛啊腫麼辦)
洛谷oj 1030 水水水
題目描述 給出一棵二叉樹的中序與後序排列。求出它的先序排列。約定樹結點用不同的大寫字母表示,長度 8 輸入輸出格式 輸入格式 2行,均為大寫字母組成的字串,表示一棵二叉樹的中序與後序排列。輸出格式 1行,表示一棵二叉樹的先序。輸入輸出樣例 輸入樣例 1 badc bdca 輸出樣例 1 abcd 這...
acmoj 算路程 水水
在群裡看到這個比賽就註冊做了一道,這個真水,acmoj上的第一道題,貼上來紀念紀念,事實上是我現在做個題目就像貼上來 include include include include includeusing namespace std struct node b 10005 int a 10005 ...
水題 陣列重建
題目 陣列重建 description durong喜歡玩陣列,但是他不小心弄丟了乙個陣列的一些數字。他只知道原來陣列的元素滿足a i a i 1 1 m 1 i n 並且都大於等於0。現在的陣列中弄丟的數字用 1表示。你需要幫助durong找回丟失的元素,重建陣列。input 輸入第一行為兩個整數...