[POI2014]Criminals
题目大意:
给你一个长度为$n(n\le10^6)$的颜色序列,其中每个颜色互不相同。两个人$A$和$B$分别从某个点出发从左往右、从右往左任意地选择颜色,然后在中间的某一点相遇。分别给出两人所选择的颜色序列,求有哪些点可能是相遇点。
思路:
$O(n)$线性扫出对于每个点$i$,颜色序列$A$在$i$及$i$前结束时,$A$左端点最右的位置$l_i$,颜色序列$B$在$i$及$i$后结束时,$B$右端点最右的位置$r_i$。
枚举每个点作为相遇点,判断区间$[1,l_i)$和$(r_i,n]$有没有相同颜色即可。因为$l_i$和$r_i$都是单调不降,因此复杂度还是$O(n)$的。
1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch^'0'; 7 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 8 return x; 9 } 10 const int N=1e6+2; 11 int c[N],s1[N],s2[N],pos1[N],pos2[N],f[N],l[N],r[N],ans[N]; 12 int main() { 13 const int n=getint(),m=getint(); 14 for(register int i=1;i<=n;i++) c[i]=getint(); 15 s1[0]=getint(),s2[0]=getint(); 16 for(register int i=1;i<=s1[0];i++) f[pos1[s1[i]=getint()]=i]=0; 17 for(register int i=1;i<=n;i++) { 18 if(pos1[c[i]]) f[pos1[c[i]]]=pos1[c[i]]==1?i:f[pos1[c[i]]-1]; 19 l[i]=f[s1[0]]; 20 } 21 for(register int i=1;i<=s2[0];i++) f[pos2[s2[i]=getint()]=i]=n+1; 22 for(register int i=n;i>=1;i--) { 23 if(pos2[c[i]]) f[pos2[c[i]]]=pos2[c[i]]==1?i:f[pos2[c[i]]-1]; 24 r[i]=f[s2[0]]; 25 } 26 for(register int i=1;i<=m;i++) pos1[i]=pos2[i]=0; 27 for(register int i=1;i<=n;i++) pos2[c[i]]++; 28 for(register int i=1,tmp=0;i<=n;i++) { 29 for(register int j=l[i-1];j<l[i];j++) { 30 if(!pos1[c[j]]++&&pos2[c[j]]) tmp++; 31 } 32 for(register int j=r[i];j>r[i-1];j--) { 33 if(!--pos2[c[j]]&&pos1[c[j]]) tmp--; 34 } 35 if(c[i]==s1[s1[0]]&&tmp) ans[++ans[0]]=i; 36 } 37 printf("%d\n",ans[0]); 38 for(register int i=1;i<=ans[0];i++) { 39 printf("%d%c",ans[i]," \n"[i==ans[0]]); 40 } 41 return 0; 42 }