• Codeforces 1136D


    题目链接:https://codeforces.com/problemset/problem/1136/D

    题意:

    给出 $1 sim n$ 的某个排列 $p$,再给出若干 $(x,y)$ 表示当序列中出现 $x,y$ 时,两者可以交换位置。问序列中最末尾的数可以前进多少步。

    题解:

    如果 $p[n-1]$ 可以与 $p[n]$ 交换位置,那么肯定是立刻交换,因为首先 $p[n-1]$ 只能最多只能产生 $1$ 步的贡献,同时就算把 $p[n-1]$ 往前换,等到在未来某个时刻再跟 $p[n]$ 交换,也不可能使得前进步数更多(自己画画就能明白),因此不如立刻换掉。

    如果此时 $p[n-1]$ 与 $p[n]$ 不能交换位置,那么想要前进,必然要找一个能 $p[x]$ 能和我 $p[n]$ 交换的,和上面同样的道理,找远的 $x$ 不会比找近的 $x$ 更优,因此优先找最近的那个 $p[x]$ 来跟我交换位置即可。

    (这题的序列存储我用了数组模拟链表,时间复杂度是 $O(n log m)$,不知道我是不是写复杂了……)

    AC代码:

    #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;
    }
  • 相关阅读:
    安全探讨之用Win32汇编写双进程守护
    LightTPD 1.4.12
    mysql4存在mysql5没有的性能成绩
    gcolor2-拾色器
    solaris 中挂载usb移动硬盘
    Browsershots:测试你的 Web 企图
    MythTV 0.20
    XorgEdit:xorg.conf 编纂器
    pci168c,1c无线网卡如何在64位Solaris系统上运用
    Fedora8中批改磁盘卷标
  • 原文地址:https://www.cnblogs.com/dilthey/p/10555908.html
Copyright © 2020-2023  润新知