POI2014 Criminals

Criminals

POI2014

題意

1.有一個顏色序列

2.有兩個人會分別從左往右和從右往左走,並在途中任意取走幾個格子裏面的顏色,直到兩個人相遇。

3.已知兩個人所取走的顏色序列,並且保證這兩 個顏色序列的最後一個元素都是同一種顏色(代表兩個人相遇的點)。

4.兩個人出發點的顏色都是相同的,並且他們不會取出發點的顏色.

5.不存在任意一個顏色在這兩個序列中出現兩次(但可以分別在兩個序列中出現一次)。

6.問可能的相遇點有多少個,是那些點。

1.枚舉每種顏色的點對
(顏色相同情況下找相離最遠的,即左邊起第一次出現的位置,與右邊起第一次出現的位置)

2.需要找到他們最近在哪裏可以滿足各自的顏色序列。
①預處理每個顏色的後繼(對於1來說),
②預處理每個顏色的前驅(對於2來說)
③預處理每個點向後(前)最早碰到序列(取色序列)中第一個元素的位置

用並查集查找,這樣同一段序列只會被掃描一次
(找到當前顏色上,第一個顏色序列的位置,並查集查找的顏色序列末尾)

具體代碼

#include<bits/stdc++.h>
using namespace std;
const int M=1000005;
int n,K,A[M];
int B[M],C[M],L1,L2;
int nxt[M],pre[M],pr[M],nx[M],pos[M],last[M];
int mark[M],stk[M],top;
int get_nxt(int x) {
    top=0;
    while(nxt[x]!=x){
        stk[++top]=x;
        x=nxt[x];
    }
    while(top)nxt[stk[top--]]=x;
    return x;
}
int get_pre(int x) {
    top=0;
    while(pre[x]!=x){
        stk[++top]=x;
        x=pre[x];
    }
    while(top)pre[stk[top--]]=x;
    return x;
}
int main() {
    scanf("%d %d",&n,&K);
    for(int i=1; i<=n; i++) {
        scanf("%d",&A[i]);
    }
    scanf("%d %d",&L1,&L2);
    for(int i=1; i<=K; i++)C[i]=pos[i]=0;
    for(int i=1; i<=L1; i++) {
        scanf("%d",&B[i]);
        C[B[i]]=i;
    }
    for(int i=n; i>=1; i--) {
        nx[i]=pos[B[1]];
        pos[A[i]]=i;
        if(!C[A[i]])continue;
        int p=C[A[i]];
        if(p==L1)nxt[i]=i;
        else nxt[i]=pos[B[p+1]];
    }
    for(int i=1; i<=K; i++)C[i]=pos[i]=0;
    for(int i=1; i<=L2; i++) {
        scanf("%d",&B[i]);
        C[B[i]]=i;
    }
    for(int i=1; i<=n; i++) {
        pr[i]=pos[B[1]];
        pos[A[i]]=i;
        if(!C[A[i]])continue;
        int p=C[A[i]];
        if(p==L2)pre[i]=i;
        else pre[i]=pos[B[p+1]];
    }
    for(int i=1; i<=K; i++)pos[i]=last[i]=0;
    for(int i=1; i<=n; i++) {
        if(!pos[A[i]])pos[A[i]]=i;
    }
    for(int i=n; i>=1; i--) {
        if(!last[A[i]])last[A[i]]=i;
    }
    for(int i=1; i<=K; i++) {
        int L=pos[i],R=last[i];
        if(!L||!R||L>R)continue;
        L=get_nxt(nx[L]);
        R=get_pre(pr[R]);
        if(!L||!R||L>R)continue;
        mark[L]++,mark[R+1]--;
    }
    int cnt=0,res=0;
    for(int i=1; i<=n; i++) {
        res+=mark[i];
        if(res&&A[i]==B[L2])cnt++;
    }
    printf("%d\n",cnt);
    res=0;
    for(int i=1; i<=n; i++) {
        res+=mark[i];
        if(res&&A[i]==B[L2])printf("%d ",i);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章