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;
}
相关文章
相关标签/搜索