Codeforces Round #215 (Div. 2) D. Sereja ans Anagrams
http://codeforces.com/contest/368/problem/D
题意:有a、b两个数组,a数组有n个数,b数组有m个数,现在给出一个p,要你找出所有的位置q,使得位置q q+p q+2*p .....q+(m-1)*p 经过一定的操作(不改变数据大小)全等于b数组。
思路:首先肯定对a数组离散,然后二分对a、b数组分配好离散后的值。其实我们只需要枚举0————p位置,哈希记录,然后从q----一直滚到q(m-1)*p>=n,对于一个数据,出来第一个数,进去最后一个数。
这样,如果没有避免对b数组扫描一次,那么还是会超时,额,我在这里超时了几次。这个题目的核心就是如何避免再一次扫描b数组,因为我要判断挑出来的m个值与b数组全等........其实可以这样,我们把b数组里的数据都记录一次,比如b[10]={1,2,3,1,2,3,4,5,1,2};
那么我们对于b数组哈希的话,就是vist[1]=3 vist[2]=3 vist[3]=2 vist[4]=1 vist[5]=1 那么,如果说要有一个数来记录b有几种不想等的数据的话,那么k=5;
那么同样的,我们会对于从a数组里面挑出来的m个值进行哈希,那么有vist1[1] vist1[2] vist1[3] vist1[4] vist1[5];
当且仅当,vist[1]==vist1[1] vist[2]==vist1[2] vist[3]==vist1[3] vist[4]==vist1[4] vist[5]==vist1[5]时,与b全等,那么也就是说
在严格挑选出来的m各值,要有m种数,并且,这m种数要等于k,如此就可以说挑出来的m个数就是b数组.........
那么其实,只要有vist[i]>0时 有vist[i]==vist1[i] 那就m++ 如果某个操作,弹出来一个值,使得原本vist[i]>0时 有vist[i]==vist1[i]的,现在不想等了,那么就m--;
ac代码:
额,还需要注意一点,这个数据有的地方会超int型,所以,用__int64比较好把 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int vist[200005],vist1[200005]; int a[200005],b[200005],s[200005]; int total[200005],vist2[200005]; int vist3[200005]; int erfen(int ll,int rr,int ans) { while(ll<=rr) { int mid=(ll+rr)/2; if(s[mid]>ans) rr=mid-1; else ll=mid+1; } return rr; } int main() { int n,m,p; while(scanf("%d%d%d",&n,&m,&p)>0) { for(int i=0; i<n; i++) { scanf("%d",&a[i]); s[i]=a[i]; } sort(s,s+n); int cnt=1; for(int i=1; i<n; i++) if(s[i]!=s[i-1]) s[cnt++]=s[i]; sort(s,s+cnt); memset(vist,0,sizeof(vist)); memset(vist1,0,sizeof(vist1)); memset(vist2,0,sizeof(vist2)); memset(vist3,0,sizeof(vist3)); //for(int i=0;i<n;i++) //vist[s[i]]=i+1; for(int i=0; i<m; i++) scanf("%d",&b[i]); for(int i=0; i<n; i++) { int id=erfen(0,cnt-1,a[i]); vist[id]=1; a[i]=id; } int flg=1; int ans=0,ans1=0; for(int i=0; i<m; i++) { int id=erfen(0,cnt-1,b[i]); if(b[i]==s[id]) { if(vist1[id]==0) ans++; vist1[id]++; } else { flg=0; break; } b[i]=id; //vist2[id]=1; } if(flg==0) { printf("0\n"); continue; } int sum=0; for(int i=0; i<p; i++) { if((__int64)i+(__int64)(m-1)*(__int64)p>=n) break; for(int j=0; j<m; j++) { if((__int64)i+(__int64)j*(__int64)p>=n) break; int y=a[i+j*p]; if(vist1[y]) { vist2[y]++; if(vist2[y]==vist1[y]) { ans1++; vist3[y]=0; } if(vist2[y]>vist1[y]&&vist3[y]==0) { ans1--; vist3[y]=1; } } } if(ans1==ans) { total[sum++]=i; } for(int j=i+p; (__int64)j+(__int64)(m-1)*(__int64)p<n;j+=p) { int y=a[j-p]; if(vist1[y]) { if(vist2[y]==vist1[y]) { ans1--; vist3[y]=0; } vist2[y]--; if(vist2[y]==vist1[y]) { ans1++; vist3[y]=0; } } y=a[j+(m-1)*p]; if(vist1[y]) { vist2[y]++; if(vist2[y]==vist1[y]) { ans1++; vist3[y]=0; } if(vist2[y]>vist1[y]&&vist3[y]==0) { ans1--; vist3[y]=1; } } if(ans1==ans) { total[sum++]=j; } } for(int k=0;k<m;k++) { vist2[b[k]]=0; vist3[b[k]]=0; ans1=0; } } printf("%d\n",sum); sort(total,total+sum); for(int i=0; i<sum; i++) { if(i==0) printf("%d",total[i]+1); else printf(" %d",total[i]+1); } printf("\n"); } return 0; }