[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher 题解报告
来刷kuangbin字符串了,字符串处理在ACM中是很重要的,一般比赛都会都1——2道有关字符串处理的题目,而且不会很难的那种,大多数时候都是用到一些KMP的性质或者找规律。
点击标题可跳转至VJ比赛题目链接。
A - Number Sequence
题意就是让你去找在串A找串B首次出现的位置,现在串不是字符串,而是数字串,所以用int数组存储即可,然后就是裸KMP。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; int n,m;
int a[],b[];
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -;
while(i < n){
if(j == - || b[i] == b[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int KMP(){
getnext();
int i = ,j = ;
while(i < n){
if(j == - || a[i] == b[j])
++i,++j;
else
j = nxt[j];
if(j == m)
return i-m+;
}
return -;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
cin>>n>>m;
for(int i = ; i < n; i++)
cin>>a[i];
for(int i = ; i < m; i++)
cin>>b[i];
cout << KMP() << endl;
} return ;
}
B - Oulipo
题意就是找字符串A在字符串B中出现的次数,还是裸KMP,当j指针等于字符串A长度时,次数加一即可。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; string a,b;
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -,len = b.size();
while(i < len){
if(j == - || b[i] == b[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int KMP(){
getnext();
int i = ,j = ,sum = ,len1 = a.size(),len2 = b.size();
while(i < len1){
if(j == - || a[i] == b[j])
++i,++j;
else
j = nxt[j];
if(j == len2)
sum++;
}
return sum;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
cin>>b>>a;
cout << KMP() << endl;
} return ;
}
C - 剪花布条
同上一题,不过这题被匹配过的串就不能在被匹配了,所以使next数组中next[len] = 0,即当j等于len时候,从0开始重新匹配。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; string a,b;
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -,len = b.size();
while(i < len){
if(j == - || b[i] == b[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
nxt[len] = ;
} int KMP(){
getnext();
int i = ,j = ,sum = ,len1 = a.size(),len2 = b.size();
while(i < len1){
if(j == - || a[i] == b[j])
++i,++j;
else
j = nxt[j];
if(j == len2)
sum++;
}
return sum;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>a && a[] != '#'){
cin>>b;
cout << KMP() << endl;
} return ;
}
D - Cyclic Nacklace
题意就是最少在当前串后面加几个字符使得当前串变成一个循环串。
思路:当前串记为S串,根据next数组的定义有S[0,next[k]-1] = S[k - next[k],k-1],既前面的部分是完全相等的,那么有S[0,next[len]-1] = S[len-next[len],len-1],所以S串的一个最长循环节就是len-next[len]。
Why?
来看下面这个手稿= =
解决了这个问题之后,就好做了,如果本来就是一个循环串即len%(len-next[len])=0则输出0,否则输出补成循环串需要多少字符。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; string b;
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -,len = b.size();
while(i < len){
if(j == - || b[i] == b[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
cin>>b;
getnext();
int len = b.size();
int cnt = len/(len - nxt[len]);
if(nxt[len] > && len % (len-nxt[len]) == )
cout << << endl;
else
cout << (cnt+)*(len-nxt[len]) - len << endl;
} return ;
}
E - Period
题意就是在串的前缀中找循环串,输出位置并输出循环节次数。
思路同上,每次判断是否循环串即可。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; string a;
int n;
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -;
while(i < n){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int tot = ;
while(cin>>n && n){
cin>>a;
getnext();
cout << "Test case #" << tot++ << endl;
for(int i = ; i <= n; i++){
//cerr << nxt[i] << ' ';
if(nxt[i] > && (i)%(i-nxt[i]) == )
cout << i << " " << i/(i-nxt[i]) << endl;
}
cout << endl;
} return ;
}
F - The Minimum Length
原OJ出了点问题,没法做。
G - Power Strings
定义A*B就是把B接在串A后面,A^k = A*A^(k-1);现在给你一个串S,问把它写成A^n形式,n最大是多少(A串要你自己找)。
很简单的一个判断循环串的题,如果串是循环串的话,数组循环次数,否则输出1即可。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std; string a;
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -,len = a.size();
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>a && a[] != '.'){
getnext();
int len = a.size();
if(len%(len-nxt[len]) != )
cout << << endl;
else
cout << len / (len - nxt[len]) << endl;
} return ;
}
H - Seek the Name, Seek the Fame
题意:在字符串S中,找到字符串A使得A既是S的前缀串,又是S的后缀串,并输出A串第一次出现的位置。
思路:还是根据next数组的性质,有S[0,next[len]-1] = S[len-next[len],len-1],所以S[0,next[len]-1]是一个满足题意的串,且有S[0,next[next[len]]-1] = S[len-next[next[len]],len-1],所以S[0,next[next[len]]-1]也是一个满足题意的串,所以可以依次往下找直到next数组值为0位置。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <stack>
using namespace std; string a;
int nxt[]; void getnext(){
nxt[] = -;
int i = , j = -,len = a.size();
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>a && a[] != '.'){
getnext();
stack<int> q;
int len = a.size();
int cnt = ,j = nxt[len];
while(j > ){
q.push(j);
j = nxt[j];
}
while(!q.empty()){
cout << q.top() << " ";
q.pop();
}
cout << len << endl;
} return ;
}
I - Blue Jeans
找多个串的最长公共子串,且若是字串长度小于3输出"no significant commonalities"。
开始我还在想这不DP题吗= =,然后发现每组最多10个串,且串长度不超过60,所以直接暴力匹配每个字串。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
using namespace std; string a,b;
int nxt[];
vector<string> v;
int m; class cmp{
public:
bool operator () (const string a, const string b) const {
if(a.size() == b.size())
return a > b;
return a.size() < b.size();
}
}; void getnext(string a){
nxt[] = -;
int i = , j = -,len = a.size();
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} bool KMP(string b,string s){
int i = ,j = ,len1 = b.size(),len2 = s.size();
getnext(s);
while(i < len1){
if(j == - || b[i] == s[j])
++i,++j;
else
j = nxt[j];
if(j == len2)
return ;
}
return ;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
cin>>m>>a>>b;
v.clear();
for(int i = ,len = a.size(); i < len; i++){
for(int j = ; i+j < len; j++){
string s = a.substr(i,j+);
if(KMP(b,s))
v.push_back(s);
}
}
m -= ;
while(m--){
cin>>b;
for(vector<string>::iterator it = v.begin(); it != v.end();){
if(!KMP(b,*it))
it = v.erase(it);
else
it++;
}
}
if(v.empty()){
cout << "no significant commonalities" << endl;
continue;
}
string ans = *max_element(v.begin(),v.end(),cmp());
if(ans.size() < )
cout << "no significant commonalities" << endl;
else
cout << ans << endl;
} return ;
}
J - Simpsons’ Hidden Talents
每组输入两个字符串A和B,找到一个最长的字符串S使得S是A的前缀串且S是B的后缀串,输出串S和S的长度。
思路:前面说了next数组有S[0,next[len]-1] = S[len-next[len],len-1],同样设主串为S,模式串为T,同样满足S[i-next[j],i-1] = T[0,next[j]-1]这个性质,当i=len时候,有S[len-next[j],len-1] = T[0,next[j]-1],那么T[0,next[j]-1]即是前缀串,S[len-next[j],len-1]为后缀串。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
using namespace std; string a,b;
int nxt[]; void getnext(){
int i = , j = -, len = a.size();
nxt[] = -;
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int KMP(){
getnext();
int i = , j = ,len1 = b.size(), len2 = a.size();;
while(i < len1){
if(j == - || b[i] == a[j])
++i, ++j;
else
j = nxt[j];
}
if(i == len1)
return j;
return ;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>a>>b){
int ans = KMP();
if(!ans)
cout << << endl;
else
cout << a.substr(,ans) << ' ' << ans << endl;
} return ;
}
K - Count the string
题意:数一个字符串每个前缀串出现的次数并%10007。
思路:直接去找每个前缀串出现的次数则需要len次KMP,肯定会TLE,所以我们不妨换个思维,我们从next数组下手,根据S[0,next[i]-1] = S[i-next[i],i-1],我们去找第i个位置的next数组,那么S[0,next[i]-1]这个前缀串也就在S[i-next[i],i-1]出现了一次,直到next数组值为0为止。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
using namespace std; int n;
string a;
int nxt[]; void getnext(){
int i = , j = -;
nxt[] = -;
while(i < n){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
int ans = ;
cin>>n>>a;
getnext();
for(int i = ; i <= n; i++){
int tp = nxt[i];
while(tp){
ans = (ans+)%;
tp = nxt[tp];
}
}
cout << (ans+n)% << endl;
} return ;
}
这个题是很好的一个题,不仅考察了next数组的性质,还转变了思维方式,从去找每个串出现次数之和变成了找每个位置包含了哪些前缀串。
L - Clairewd’s message
题意:每行输入两个字符串,第一个字符串是一个密码表,a-z对应成密码表上的字符,第二个字符串是密文+明文,密文是完整的但明文部分不全但至少有一个字符是明文,现在问最多可以补全多少个字符并输出。
思路:如果没有密文表这个东西的话就是个很简单的字符匹配,让密文部分尽量长即可,但现在有了密文所以要稍做修改,我们从(len+1)/2的位置开始KMP,因为密文完整,所以密文至少占用了一半的字符串,当然你也可以拆成两个串进行匹配。
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
using namespace std; string a,s;
int nxt[]; void getnext(){
int i = , j = -,len = a.size();
nxt[] = -;
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} void KMP(){
getnext();
int i = (a.size()+)/,j = ,len = a.size();
while(i < len){
if(j == - || s[a[i]-'a'] == a[j])
++i,++j;
else
j = nxt[j];
}
cout << a;
map<char,char> mp;
for(int i = ; i < ; i++)
mp[s[i]] = char('a'+i);
for(int i = j; i < len-j; i++)
cout << mp[a[i]];
cout << endl;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
cin>>s>>a;
KMP();
}
return ;
}
M - Substrings
输出最长公共子串的长度。不多说直接暴力,稍微优化一下,从长度最短的串开始枚举子串即可。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
using namespace std; string s[];
int nxt[];
int m; void getnext(string a){
int i = , j = -,len = a.size();
nxt[] = -;
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} bool KMP(int k,string b){
getnext(b);
int i = ,j = ,len = s[k].size();
while(i < len){
if(j == - || s[k][i] == b[j])
++i,++j;
else
j = nxt[j];
if(j == b.size())
return ;
}
return ;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int t;
cin>>t;
while(t--){
string str = "";
int tot = ;
cin>>m;
for(int i = ; i < m; i++){
cin>>s[i];
if(str.empty() || s[i].size() < str.size())
str = s[i];
}
int len = str.size();
for(int i = len; i > ; i--){
int flag = ;
for(int j = ; i+j <= len; j++){
flag = ;
string t1 = str.substr(j,i);
string t2 = t1;
//cout << t1 <<endl;
reverse(t2.begin(),t2.end());
for(int k = ; k < m; k++){
if(!KMP(k,t1) && !KMP(k,t2)){
flag = ;
break;
}
}
if(flag){
tot = ;
cout << t1.size() << endl;
break;
}
}
if(flag)
break;
}
if(!tot)
cout << << endl;
}
return ;
}
N - Corporate Identity
同上,不过这题输出最长公共字串。
代码:
#include <string>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
using namespace std; string s[];
int nxt[];
int m; class cmp{
public:
bool operator () (const string a, const string b) const {
if(a.size() == b.size())
return a > b;
return a.size() < b.size();
}
}; void getnext(string a){
int i = , j = -,len = a.size();
nxt[] = -;
while(i < len){
if(j == - || a[i] == a[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
} bool KMP(int k,string b){
getnext(b);
int i = ,j = ,len = s[k].size();
while(i < len){
if(j == - || s[k][i] == b[j])
++i,++j;
else
j = nxt[j];
if(j == b.size())
return ;
}
return ;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>m && m){
vector<string> v;
string str;
int tot = ;
for(int i = ; i < m; i++){
cin>>s[i];
if(str.empty() || s[i].size() < str.size())
str = s[i];
}
int len = str.size();
for(int i = len; i > ; i--){
int flag = ;
v.clear();
for(int j = ; i+j <= len; j++){
flag = ;
string t1 = str.substr(j,i);
for(int k = ; k < m; k++){
if(!KMP(k,t1)){
flag = ;
break;
}
}
if(flag){
tot = ;
v.push_back(t1);
}
}
if(flag || !v.empty()){
cout << *(max_element(v.begin(),v.end(),cmp())) << endl;
break;
}
}
if(!tot)
cout << "IDENTITY LOST" << endl;
}
return ;
}
O - String Problem
给你一个字符串,每次可以位移一位即把首字母放到尾部,然后问变成字典序最小的串该如何移动且这个串出现了几次,变成字典序最大的串该如何移动且这个串出现了几次。
最大最小表示法模板,不多说。出现几次判断是否循环串即可。
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std; string s;
int nxt[]; void getnext(string str){
int i = , j = -, len = str.size();
nxt[] = -;
while(i < len){
if(j == - || str[i] == str[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
}
int posmin(int len){
int i=,j=,k=;
while(i<len&&j<len&&k<len){
int pan=s[(i+k)%len]-s[(j+k)%len];
if(!pan)
k++;
else{
if(pan>)
i+=k+;
else
j+=k+;
if(i==j)
j++;
k=;
}
}
return min(i+,j+);
} int posmax(int len){
int i=,j=,k=;
while(i<len&&j<len&&k<len){
int pan=s[(i+k)%len]-s[(j+k)%len];
if(!pan)
k++;
else{
if(pan>)
j+=k+;
else
i+=k+;
if(i==j)
j++;
k=;
}
}
return min(i+,j+);
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>s){
int cnt = ;
int len = s.size();
getnext(s);
if(len%(len-nxt[len])==)
cnt = len/(len-nxt[len]);
cout << posmin(len) << ' ' << cnt << ' ' << posmax(len) << ' ' << cnt << endl;
}
}
P - How many
问一组字符串去重后还剩多少,比较方式是只要A能通过位移得到B,就看成相同串,具体题目有解释。
思路:直接去判断A能否位移得到B很麻烦,换个思路我们把字符串转化成相同样式,然后不久可以直接比较了吗,利用最大最小表示法,我们把输入串转化为最大或最小表示法丢进set即可。
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std; string s;
int nxt[]; void getnext(string str){
int i = , j = -, len = str.size();
nxt[] = -;
while(i < len){
if(j == - || str[i] == str[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
}
string posmin(string s,int len){
int i=,j=,k=;
while(i<len&&j<len&&k<len){
int pan=s[(i+k)%len]-s[(j+k)%len];
if(!pan)
k++;
else{
if(pan>)
i+=k+;
else
j+=k+;
if(i==j)
j++;
k=;
}
}
int ans = min(i,j);
string res = s.substr(ans,len-ans) + s.substr(,ans);
return res;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int n;
while(cin>>n){
set<string> v;
for(int i = ; i < n; i++){
cin>>s;
v.insert(posmin(s,s.size()));
}
cout << v.size() << endl;
}
}
Q - Period II
没法做。
R - Teacher YYF
神题= =,给你单词的词性,然后给你句子让你判断是否有语法错误,我的思路就是把所有合法情况枚举出来。但暴露了英语不好的事实,WA了,然后发现是合法情况没有找全,然后百度的qwq
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <map>
#include <sstream>
using namespace std; map<string,string> mp;
map<string,bool> ste;
map<string,char> str,fun; void init(){
fun["n."]='';
fun["pron."]='';
fun["adj."]='';
fun["adv."]='';
fun["prep."]='';
fun["art."]='';
fun["vt."]='';
fun["vi."]='';
fun["v."]=''; str[""]='A'; //介词短语
str[""]='A';
str[""]='A';
str[""]='S'; //主/宾语
str[""]='S';
str[""]='S';
str[""]='I'; //不及物谓语
str[""]='I';
str[""]='T'; //及物谓语
str[""]='T';
str[""]='V'; //通用谓语
str[""]='V';
//句子可能的总体结构
ste["SI"]=;
ste["STS"]=;
ste["SV"]=;
ste["SVS"]=;
ste["ASI"]=;
ste["ASTS"]=;
ste["ASV"]=;
ste["ASVS"]=;
ste["SAI"]=;
ste["SATS"]=;
ste["SAV"]=;
ste["SAVS"]=;
ste["SIA"]=;
ste["STAS"]=;
ste["SVA"]=;
ste["SVAS"]=;
ste["STSA"]=;
ste["SVSA"]=;
} bool check(string s){
string res = "",c = "";
for(int i = ; i < s.size(); i++){
c += s[i];
if(str[c] > ){
res += str[c];
c = "";
}
}
res += c;
if(ste[res])
return true;
return false;
} string work(string s){
stringstream ss(s);
string st,ans;
while(ss>>st){
int len = st.size(),flag = ;
st[] = tolower(st[]);
if(st[len-] == '.'){
flag = ;
st.erase(--st.end());
}
if(st[len-] == ',')
st.erase(--st.end());
ans += fun[mp[st]];
if(flag && !check(ans))
return "NO";
}
return "YES";
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
int n,m;
init();
while(cin>>n>>m){
mp.clear();
string s,s1,s2;
for(int i = ; i < n; i++){
cin>>s1>>s2;
//cout << s1 << " " << s2 <<endl;
mp[s1] = s2;
}
cin.get();
for(int i = ; i < m; i++){
getline(cin,s);
cout << work(s) << endl;
}
}
}
S - Best Reward
给你个价值表,a-z分别就对应相应价值,然后让你找最长回文串并输出价值和。
马拉车裸题。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <iomanip>
#include <climits>
using namespace std; int n;
int p[],sum[],val[];//sum为前i个字符价值和
int per[],pos[];//per标记前i个字符为回文串,pos标记后i个字符为回文串 int manacher(string t){
int len = t.size(),id=,ans=INT_MIN,temp=;
for(int i = ; i <= len; ++i)
sum[i] = sum[i-] + val[t[i-]-'a'];
string s = "*#";
for(int i = ; i < t.size(); ++i) {
s += t[i];
s += "#";
}
for(int i = ; i < len*+; ++i){
if(p[id] + id > i)
p[i]=min(p[*id-i],p[id]+id-i);
else
p[i] = ;
while(s[i-p[i]] == s[i+p[i]])
++p[i];
if(id+p[id] < i+p[i])
id = i;
if(i-p[i] == )
per[p[i]-] = n+;//表示前缀(前p[i]-1个字符)是回文串
if(i+p[i] == *len+)
pos[p[i]-] = n+;//表示后缀(后p[i]-1个字符)是回文串
}
for(int i = ; i < len; ++i){
if(per[i] == n+)
temp += sum[i];
if(pos[len-i] == n+)
temp += sum[len]-sum[i];
if(temp > ans)
ans = temp;
temp=;
}
return ans;
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
cin>>n;
while(n--){
string s;
for(int i = ; i < ; ++i)
cin >> val[i];
cin>>s;
cout << manacher(s) << endl;
}
return ;
}
T - Finding Palindromes
还没做。
U - Palindrome
最长回文串。懒得贴代码了。
V - 吉哥系列故事――完美队形II
还没做。
W - Girls' research
还没做。
X - 最长回文
最长回文串。
代码:
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std; string t;
int rad[]; void manacher(int len) {
string s = "*#";
for(int i = ; i < t.size(); ++i) {
s += t[i];
s += "#";
}
for (int i=,j=,k; i < len; i+=k) {
while (s[i-j-] == s[i+j+]) ++j;
rad[i] = j;
for (k = ; k <= rad[i] && rad[i-k] != rad[i]-k; ++k) {
rad[i+k] = min(rad[i-k], rad[i]-k);
}
j = max(j-k, );
}
} int main(){
ios_base::sync_with_stdio(),cin.tie(),cout.tie();
while(cin>>t){
int len = t.size()*+;
manacher(len);
cout << *max_element(rad,rad+len) << endl;
}
return ;
}
Y - Wow! Such Doge!
还没做。
Z - Theme Section
还没做。
还有几道题没做,尽快补上。主要还是考察KMP的next数组的性质,然后还有一些前后缀的题也可以用exKMP来做,但暂时偷个懒先水一遍吧。
[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher 题解报告的更多相关文章
- [kuangbin带你飞]专题十 匹配问题
A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找 ID Origin Title 61 / 72 Problem A HD ...
- [kuangbin带你飞]专题十 匹配问题 一般图匹配
过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂 抄了一遍 ...
- [kuangbin带你飞]专题十五 数位DP
ID Origin Title 62 / 175 Problem A CodeForces 55D Beautiful numbers 30 / 84 Problem B HD ...
- [kuangbin带你飞]专题十 匹配问题 二分匹配部分
刚回到家 开了二分匹配专题 手握xyl模板 奋力写写写 终于写完了一群模板题 A hdu1045 对这个图进行 行列的重写 给每个位置赋予新的行列 使不能相互打到的位置 拥有不同的行与列 然后左行右列 ...
- [kuangbin带你飞]专题十 匹配问题 二分图多重匹配
二分图的多重匹配问题不同于普通的最大匹配中的"每个点只能有最多一条边" 而是"每个点连接的边数不超过自己的限定数量" 最大匹配所解决的问题一般是"每个 ...
- 【算法系列学习】DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus
A - Max Sum Plus Plus https://vjudge.net/contest/68966#problem/A http://www.cnblogs.com/kuangbin/arc ...
- [kuangbin带你飞]专题十四 数论基础
ID Origin Title 111 / 423 Problem A LightOJ 1370 Bi-shoe and Phi-shoe 21 / 74 Problem B ...
- [kuangbin带你飞]专题十二 基础DP1
ID Origin Title 167 / 465 Problem A HDU 1024 Max Sum Plus Plus 234 / 372 Problem B HDU 1 ...
- [kuangbin带你飞]专题十 匹配问题 二分图最大权匹配
二分图最大权匹配有km算法和网络流算法 km算法模板默认解决最大权匹配的问题 而使用最小费用最大流 是解决最小权匹配问题 这两种办法都可以求最大最小权 需要两次取反 TAT 感觉讲km会很难的样子.. ...
随机推荐
- 维恩贝特面试JAVA后台开发
1 自我介绍 2 链表和数组区别(数组空间连续,且有下标,查找快,但是增删数据效率不高,链表的空间不连续,查找起来慢,但是对数据的增删效率高,链表可以随意扩大,数组不能) 3 sort方法的实现 (A ...
- 调试应用不发愁,免安装的 curl 来帮忙
1 cURL简介 cURL是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行.它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称cURL为下载工具.cURL还包含了用于程序开 ...
- c语言的图形库
图形库链接http://www.easyx.cn/ 使用图形库头文件easyx.h或graphics.h 同样在里面下载图形库帮助文档进行查询 vs vc都可使用图形库 图形库窗口: initgrap ...
- Ubuntu系统开发环境完整搭建
安装搜狗输入法 点击我下载哦 idea快捷键冲突 输入发占用快捷键.撤掉输入法的快捷键.还有系统自带快捷键也要取消. 安装deepin-terminal 在tools工具包中找到deepin-term ...
- Spring源码剖析7:AOP实现原理详解
前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...
- ctpn+crnn 训练数据集生成
1. https://github.com/Belval/TextRecognitionDataGenerator 2. https://textrecognitiondatagenerator.re ...
- C++ 并发编程之互斥锁和条件变量的性能比较
介绍 本文以最简单生产者消费者模型,通过运行程序,观察该进程的cpu使用率,来对比使用互斥锁 和 互斥锁+条件变量的性能比较. 本例子的生产者消费者模型,1个生产者,5个消费者. 生产者线程往队列里放 ...
- ZYNQ Block Design中总线位宽的截取与合并操作
前言 在某些需求下,数据的位宽后级模块可能不需要原始位宽宽度,需要截位,而某些需求下,需要进行多个数据的合并操作. 在verilog下,截位操作可如下所示: wire [7:0] w_in; wire ...
- log4j配置相对路径
整理自网上: 一般在我们开发项目过程中,log4j日志输出路径固定到某个文件夹,这样如果我换一个环境,日志路径又需要重新修改,比较不方便, 1.log4j的FileAppender本身就有这样的机制, ...
- 【故障公告】再次出现数据库 CPU 居高不下的问题以及找到问题的线索
非常非常抱歉,今天上午的故障又一次给大家带来麻烦了,再次恳请大家的谅解. 在昨天升级阿里云 RDS SQL Server 实例的配置后(详见昨天的博文),万万没有想到,今天上午更高配置的阿里云 RDS ...