(还在整理,纯记录)
7-1 探索者的银淞止境
暴力做法
(截止了没法测试对不对,但样例都过了)
void solve()
{
cin>>n>>m;
cin>>a>>b;
for(int t=0;t<a.size();t++)
{
int ans=0;
for(int i=0;i<b.size();i++)
{
if(b[i]==a[t])
{
int x=i;
int y=t;
int cnt=0;
while(b[x]==a[y]&&x<b.size()&&y<a.size())
{
cnt++;
x++;
y++;
}
ans=max(ans,cnt);
}
}
s[t]=ans;
}
for(int i=0;i<n;i++) cout<<s[i]<<" ";
}
kmp做法
其实只是一个板子题
(校赛的时候kmp已经忘的差不多了,暴力却没敢写,悔的肠子都青了QAQ)
int find(int ne[],int n,string str,string t)
{
int ans=0;
str=" "+str;
t=" "+t;
for(int i=2,j=0;i<=str.size()-1;i++)
{
while(j&&str[i]!=str[j+1])
{
j=ne[j];
}
if(str[i]==str[j+1]) j++;
ne[i]=j;
}
for(int i=1,j=0;i<=t.size()-1;i++)
{
while(j&&t[i]!=str[j+1])
{
j=ne[j];
}
if(t[i]==str[j+1])
{
j++;
}
ans=max(ans,j);
if(j==str.size())
{
j=ne[j];
}
}
return ans;
}
void solve()
{
cin>>n>>m;
cin>>s>>t;
for(int i=0;i<n;i++)
{
string str=s.substr(i);
int ne[N];
cout<<find(ne,str.size(),str,t)<<" ";
}
}
P4391 [BOI2009] Radio Transmission 无线传输
寻找最短周期
kmp的一个结论:|S|=border+T
想要T最小,就要找到最大border
然后就是板子题了
void solve()
{
cin>>la;
cin>>a+1;
for(int i=2,j=0;i<=la;i++)
{
while(j&&a[i]!=a[j+1]) j=ne[j];
if(a[i]==a[j+1])
{
j++;
ne[i]=j;
}
}
int ans=la-ne[la];
cout<<ans<<endl;
}
P2375 [NOI2014] 动物园
这道题真的很不错,做完以后对kmp的next数组有了更深的认识
注意这个代码的ans数组是包含重叠情况的
如何去除重叠的?
可以利用next数组的原理
利用next数组往前找,找到符合要求的答案个数
(注意不用更新j,因为前面的i满足了那i+1也满足)
int ne[N];
char s[N];
int ans[N];
int MOD=1e9+7;
void solve()
{
memset(ans,0,sizeof(ans));
memset(ne,0,sizeof(ne));
ans[0]=0;
ans[1]=1;
cin>>s+1;
int l=strlen(s+1);
for(int i=2,j=0;i<=l;i++)
{
while(j&&s[i]!=s[j+1])
{
j=ne[j];
}
if(s[i]==s[j+1])
{
j++;
}
ne[i]=j;
ans[i]=ans[j]+1;
}
int cnt=1;
for(int i=1,j=0;i<=l;i++)
{
while(j&&(s[i]!=s[j+1])) j=ne[j];
if(s[i]==s[j+1]) j++;
while((j<<1)>i) j=ne[j];
cnt=(cnt*(ll)(ans[j]+1))%MOD;
}
cout<<cnt<<endl;
}
P3435 [POI2006] OKR-Periods of Words
换句话说就是寻找每个前缀的最小border
求出next数组,然后利用next数组对每个前缀找最小border
注意找到后可以标记一下,防TLE(感觉有点像路径压缩?)
RE的话是数组开小了
//寻找每个前缀的最小border
int n;
string s;
int ne[N];
void solve()
{
int ans=0;
cin>>n;
cin>>s;
s=" "+s;
for(int i=2,j=0;i<s.size();i++)
{
while(j&&s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
}
for(int i=1;i<s.size();i++)
{
int k=i;
while(ne[k]!=0) k=ne[k];
if(ne[i]!=0) ne[i]=k;
ans=ans+i-k;
}
cout<<ans<<endl;
}