KMP上跑浮动的模式串
一个农场主有N头牛,每个牛都以它身上的斑点数作为标志,以斑点数作为标准对牛进行rank排序,定义牛的序列的相同性为第i头牛及其之前的牛的比他rank小的数量和与他rank相同的数量,比如:
1 4 4 3 2 1 和 2 10 10 7 3 2 是一样的模式串
要求数有多少个符合要求的模式串,并输出每个符合要求的子串的起始位置。
KMP!!!太强啦,将这个浮动的串转换一下,只要能正确找出两个串等价的条件,而且在该条件下满足后面新加进来的元素不会影响前面匹配的合法性,就可以用KMP解决,虽然代码长了一点……此处为kuangbin的模板,加了一点注释的理解
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 100010;
const int MAXM = 25010;
int a[MAXN];
int b[MAXM];
int n,m,s;
int as[MAXN][30];
int bs[MAXM][30];
void init()
{
for(int i=0;i<n;i++)
{
if(i==0)
{
for(int j=1;j<=25;j++)
as[i][j]=0;
}
else
{
for(int j=1;j<=25;j++)
as[i][j]=as[i-1][j];
}
as[i][a[i]]++;
}
for(int i=0;i<m;i++)
{
if(i==0)
{
for(int j=1;j<=25;j++)
bs[i][j]=0;
}
else
{
for(int j=1;j<=25;j++)
bs[i][j]=bs[i-1][j];
}
bs[i][b[i]]++;
}
}
int Next[MAXN];
void kmp_pre() //处理出Next数组
{
int i,j;
j=Next[0]=-1;
i=0;
while(i<m)
{
int t11=0,t12=0,t21=0,t22=0;
for(int k=1;k<b[i];k++) // t11 从i往前j个牛有多少个比bi小的
{
if(i-j>0)
t11+=bs[i][k]-bs[i-j-1][k];
else
t11+=bs[i][k];
}
if(i-j>0) // t22 从i往前j个牛,有多少个和bi一样的
t12=bs[i][b[i]]-bs[i-j-1][b[i]];
else
t12=bs[i][b[i]];
for(int k=1;k<b[j];k++) //t21 第j头牛之前有多少个比bj小的
{
t21+=bs[j][k];
}
t22=bs[j][b[j]]; //t22 第j头牛之前有多少个和bj一样的
if(j==-1 || (t11==t21 && t12==t22)) //转化为正常kmp思路
{
Next[++i]=++j;
}
else
j=Next[j];
}
}
vector<int> ans;
void kmp()
{
ans.clear();
int i,j;
kmp_pre();
i=j=0;
while(i<n)
{
//和kmppre一样的处理方法,计算小于本rank的和等于本rank的
int t11=0,t12=0,t21=0,t22=0;
for(int k=1;k<a[i];k++)
{
if(i-j>0)
t11+=as[i][k]-as[i-j-1][k];
else
t11+=as[i][k];
}
if(i>j)
t12=as[i][a[i]]-as[i-j-1][a[i]];
else
t12=as[i][a[i]];
for(int k=1;k<b[j];k++)
{
t21+=bs[j][k];
}
t22=bs[j][b[j]];
if(j==-1 || (t11==t21 && t12==t22))
{
i++;
j++;
if(j>=m)
{
ans.push_back(i-m+1);
j=Next[j];
}
}
else
j=Next[j];
}
}
int main()
{
while(scanf("%d%d%d",&n,&m,&s)==3)
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<m;i++)
scanf("%d",&b[i]);
init();//处理出每个ai和它前面有多少个rank为j的,bi也处理出来
kmp();
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++)
printf("%d\n",ans[i]);
}
return 0;
}