Codeforces Round #546 (Div. 2) D. Nastya Is Buying Lunch 【思维】

版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/88648933

题目链接:http://codeforces.com/contest/1136/problem/D

让所有能和最后一个点交换的点尽可能多且连续的排列在尾部,才能让最后一个点尽可能的排在前面,这个应该比较好理解。

这里我们假想存在这么一个队列P,最初的时候,队列P的个数为0,那么就有下面这种假想的情况存在。

a1, a2, a3, a4, [P], a5

首先存在这么一个判断,a4是否能和a5交换,如果不可以,那么就把a4这个点放到队列P里面,然后继续判断a3,

如果能和a5交换,并且能够通过题目的交换规则穿过队列P的话,那么a4和a5就能连续,否则也加入队列P里面,所以队列P就是专门存放不满足题目要求的所有点的集合。

当所有的点都考虑完之后,除了队列P以外,其他都是满足题目要求的元素。

一个点要想穿过队列P内的所有点,就必须能和P内所有元素交换。

#include <bits/stdc++.h>

using namespace std;

const int Maxn = 3e5+10;

bool p[Maxn];
vector<int> G[Maxn];
int a[Maxn];

int main(void)
{
    int n, m, u, v;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
    for(int i = 0; i < m; ++i) {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
    }
    memset(p, false, sizeof(p));
    int pcnt = 0, cnt; bool ok;
    for(int i = n-2; i >= 0; --i) {
        ok = false; cnt = 0;
        int u = a[i];
        for(int j = 0; j < G[u].size(); ++j) {
            int v = G[u][j];
            if(v == a[n-1]) ok = true;
            else if(p[v]) cnt++;
        }
        if(ok && cnt == pcnt) continue;
        pcnt++; p[u] = true;
    }
    printf("%d\n", n-1-pcnt);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/88648933