Codeforces Round #215 (Div. 1) B:http://codeforces.com/problemset/problem/367/B
题意:给你两个序列a,b,然后给你一个数p,然后让你在a序列中找一个位置q,得以这个位置开始,以后每隔着aq+aq+1*(p)+.......aq+(m-1)*p,这个序列经过重新排序能够等于b,输出,所有的这样的位置。
题解:可以采用递推。先找起点是1,然后再找起点是1+p,找1+p的时候,其实只要在找1的基础上删除最前的那个数,然后再加入一个数就可以了。一次类推,然后,找2开头,2+开头。具体实现的时候,可以看下面代码。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<map> 6 using namespace std; 7 const int N=4e5+10; 8 int a[N],b[N];//记录a,b,序列 9 int counts[N],ans[N];//counts统计b序列数字出现的次数 10 int n,m,p,cnt,top; 11 int main(){ 12 while(~scanf("%d%d%d",&n,&m,&p)){ 13 map<int,int>Qa;//离散化 14 memset(counts,0,sizeof(counts)); 15 memset(a,-1,sizeof(a)); 16 memset(b,-1,sizeof(b)); 17 cnt=top=0; 18 for(int i=1;i<=n;i++){ 19 scanf("%d",&a[i]); 20 if(Qa[a[i]]==0)Qa[a[i]]=++cnt; 21 } 22 cnt=0;bool flag=false; 23 for(int i=1;i<=m;i++){ 24 scanf("%d",&b[i]); 25 if(Qa[b[i]]==0){//如果b序列中数在a中没有出现,就直接不用找了 26 flag=true; 27 } 28 counts[Qa[b[i]]]++;//统计b中数字出现的次数 29 } 30 if(!flag){ 31 for(int i=1;i<=p;i++){ 32 int ct=0,sum0=0;//每次查询记录b中数字在a中出现的次数,如果出现m次,说明等于b序列 33 for(int j=i;j<=n*2;j+=p){//注意这里是j<=2*n,虽然在n+1以后的数不会构成b序列,但是这里是为了把之前加入放入数都还原,便于下一次使用 34 counts[Qa[a[j]]]--;//入队之后次数减一 35 ct++; 36 if(counts[Qa[a[j]]]>=0)//如果次数在-1的基础上任然大于0,说明,这个数字是b中的数字 37 sum0++;//注意判断是要求大于0的,因为b的数字可能会重复 38 if(ct==m){//判断第一次达到m个数是否满足条件 39 if(sum0==m) 40 ans[++top]=i; 41 } 42 else if(ct>m){//当多余m个时候,就要把最前面的数删除,只保留m个数 43 if(counts[Qa[a[i+(ct-1-m)*p]]]>=0){//如果这个数次数大于=0,说明这个数被统计过,所以要还原 44 sum0--; 45 counts[Qa[a[i+(ct-1-m)*p]]]++; 46 } 47 else{ 48 counts[Qa[a[i+(ct-1-m)*p]]]++; 49 } 50 if(sum0==m){//判断新加入过的数有没有满足条件 51 ans[++top]=i+(ct-m)*p; 52 } 53 } 54 } 55 } 56 } 57 sort(ans+1,ans+top+1); 58 printf("%d ",top); 59 for(int i=1;i<top;i++) 60 printf("%d ",ans[i]); 61 if(top>0) 62 printf("%d ",ans[top]); 63 else 64 printf(" "); 65 } 66 }