最近的日子被考试压得喘不过气来,说好的每天水两道题又荒废了。。。
为了让写解题报告和看解题报告不那么无聊,我决定从这篇起每篇加几句心得或感慨(很大几率是废话):
数据结构是好东西,必须信手拈来,或者准备好模块,熟练得像std::sort那样,才能克服一些稍显复杂的堆砌算法的题目。
另外,KMP是神奇的算法。
poj3167
KMP&树状数组。
这题要求第一串中间是否有与第二串的匹配的子串。只不过匹配方式改成了只要大小关系相同就算可匹配。
思考后,有个重要的结论:
当某一段s1[i..j]与s2[k..l]可以匹配,那么对于s1[i..j+1]与s2[k..l+1]是否能匹配的充要条件是:
s1[i..j]中小于s1[j+1]的数和s2[k..l]中小于s2[l+1]的数个数相同,等于的个数也相同(那么大于的个数自然也相同)。
有了这个结论,就可以通过修改KMP算法求出匹配串了。
具体就是通过树状数组统计s1[i..j],s2[k..l]中小于和等于的数的个数就可以了。这题的S范围很小,暴力也应该可以。
为了让写解题报告和看解题报告不那么无聊,我决定从这篇起每篇加几句心得或感慨(很大几率是废话):
数据结构是好东西,必须信手拈来,或者准备好模块,熟练得像std::sort那样,才能克服一些稍显复杂的堆砌算法的题目。
另外,KMP是神奇的算法。
poj3167
KMP&树状数组。
这题要求第一串中间是否有与第二串的匹配的子串。只不过匹配方式改成了只要大小关系相同就算可匹配。
思考后,有个重要的结论:
当某一段s1[i..j]与s2[k..l]可以匹配,那么对于s1[i..j+1]与s2[k..l+1]是否能匹配的充要条件是:
s1[i..j]中小于s1[j+1]的数和s2[k..l]中小于s2[l+1]的数个数相同,等于的个数也相同(那么大于的个数自然也相同)。
有了这个结论,就可以通过修改KMP算法求出匹配串了。
具体就是通过树状数组统计s1[i..j],s2[k..l]中小于和等于的数的个数就可以了。这题的S范围很小,暴力也应该可以。
#include<cstdio>
#include<cstring>
using namespace std;
#define lowbit(x) (x&(-x))
#define NN 101000
int c1[NN],c2[NN],next[NN],s,ans[NN];
char s1[NN],s2[NN];
void update(int c[],int x,int val){
while(x<=s){
c[x]+=val;
x+=lowbit(x);
}
}
int query(int c[],int x){
int ret=0;
while(x){
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
void getnext(int next[],char s2[],int l2){
int i=0,j=-1;
int tail=1;
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
next[i]=j;
while(i<l2){
if ( j<0||
(query(c2,s2[j]-1)==query(c1,s2[i]-1) && query(c2,s2[j])==query(c1,s2[i]))
)
{
if (j>-1) update(c2,s2[j],1);
if (i>0) update(c1,s2[i],1);
i++;j++;next[i]=j;
}
else {
int k=j-1;
j=next[j];
for(k;k>=j;k--) {if (k<0) break;update(c2,s2[k],-1);}
int tt=i-j;
for(tail;tail<tt;tail++) update(c1,s2[tail],-1);
}
}
}
int KMP(char s1[],char s2[],int l1,int l2,int next[]){
int i,j;
int cnt=0;
int tail=0;
i=j=-1;
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
while(i<l1 && j<l2){
if(j<0||
(query(c2,s2[j]-1)==query(c1,s1[i]-1) && query(c2,s2[j])==query(c1,s1[i]))
)
{
if (j>-1) update(c2,s2[j],1);
if (i>-1) update(c1,s1[i],1);
i++;j++;
}
else {
int k=j-1;
j=next[j];
for(k;k>=j;k--) {if (k<0)break;update(c2,s2[k],-1);}
int tt=i-j;
for(tail;tail<tt;tail++) update(c1,s1[tail],-1);
}
if (j>=l2) {
ans[++cnt]=i-j;
int k=j-1;
j=next[j];
for(k;k>=j;k--) {if (k<0)break;update(c2,s2[k],-1);}
int tt=i-j;
for(tail;tail<tt;tail++) update(c1,s1[tail],-1);
}
}
return cnt;
}
int main(){
//freopen("3167in.txt","r",stdin);
int n,kk,l1,l2,cnt,i,a;
while(scanf("%d%d%d",&n,&kk,&s)!=EOF){
int l1=l2=-1;
for(i=1;i<=n;++i){
l1++;
scanf("%d",&a);
s1[l1]=a;
}
for(i=1;i<=kk;++i){
l2++;
scanf("%d",&a);
s2[l2]=a;
}
s1[++l1]=0;
s2[++l2]=0;
getnext(next,s2,l2);
cnt=KMP(s1,s2,l1,l2,next);
printf("%d\n",cnt);
for(i=1;i<=cnt;++i){
printf("%d\n",ans[i]+1);
}
}
return 0;
}