Codeforces 1136D - Nastya Is Buying Lunch - [貪心+鏈表+map]

題目連接: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;
}
相關文章
相關標籤/搜索