[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 }

 

posted @ 2018-03-29 19:47  skylee03  阅读(118)  评论(0编辑  收藏  举报