題目連接:https://codeforces.com/problemset/problem/1136/Dios
題意:c++
給出 $1 \sim n$ 的某個排列 $p$,再給出若干 $(x,y)$ 表示當序列中出現 $x,y$ 時,二者能夠交換位置。問序列中最末尾的數能夠前進多少步。數組
題解:spa
若是 $p[n-1]$ 能夠與 $p[n]$ 交換位置,那麼確定是馬上交換,由於首先 $p[n-1]$ 只能最多隻能產生 $1$ 步的貢獻,同時就算把 $p[n-1]$ 往前換,等到在將來某個時刻再跟 $p[n]$ 交換,也不可能使得前進步數更多(本身畫畫就能明白),所以不如馬上換掉。code
若是此時 $p[n-1]$ 與 $p[n]$ 不能交換位置,那麼想要前進,必然要找一個能 $p[x]$ 能和我 $p[n]$ 交換的,和上面一樣的道理,找遠的 $x$ 不會比找近的 $x$ 更優,所以優先找最近的那個 $p[x]$ 來跟我交換位置便可。blog
(這題的序列存儲我用了數組模擬鏈表,時間複雜度是 $O(n \log m)$,不知道我是否是寫複雜了……)ci
AC代碼:get
#include<bits/stdc++.h> #define pb(x) push_back(x) using namespace std; const int maxn=3e5+10; const int maxm=5e5+10; int n,m; int a[maxn]; int head,tail,pre[maxn],nxt[maxn]; map<int,bool> mp[maxn]; bool check(int x,const vector<int>& v) { for(auto y:v) if(mp[x][y]==0) return 0; return 1; } int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>n>>m; nxt[head=0]=1, pre[tail=n+1]=n; for(int i=1;i<=n;i++) cin>>a[i], pre[i]=i-1, nxt[i]=i+1; for(int i=1,x,y;i<=m;i++) cin>>x>>y, mp[x][y]=1; vector<int> need; need.pb(a[n]); for(int x=pre[n];x>head;x=pre[x]) { if(check(a[x],need)) { int L=pre[x], R=nxt[x]; nxt[L]=R, pre[R]=L; } else need.pb(a[x]); } int cnt=0; for(int p=nxt[head];p<tail;p=nxt[p]) cnt++; cout<<n-cnt<<endl; }