嘘~ 正在从服务器偷取页面 . . .

模拟赛题讲解[33]


模拟赛题讲解[33]

来自 yukuai26 2023-08-06 noi.ac #3280

题目描述

emoairx 有一个长度为 \(n\) 的初始 \((a_i=i,1 \leq i \leq n)\) 的数组, 和长度为 \(m\) 的交换序列, 他会按照序列顺序每次交换 \(2\) 个数

你需要准确地删除恰好一个交换操作, 使得数字 \(1\) 最后交换到第 \(k\) 个位置, 并输出需要删掉的交换操作的序号

如果有多个答案,输出序号最小的交换操作的序号。数据保证有解。

输入格式

第一行 \(3\) 个正整数 \(n,m,k\) , 表示 \(n\) 个数, \(m\) 个交换,最终希望数字 \(1\) 交换到第 \(k\) 个位置

接下来 \(m\) 行每行 \(2\) 个数 \(a,b\) , 表示交换 \(a,b\) 位置上的数字

输出格式

输出一个数表示序号最小的交换操作的序号,删掉这个序号后数字 \(1\) 可以交换到位置 \(k\)

输入样例

10 10 9
1 8
8 3
3 4
4 7
7 2
6 2
9 10
3 10
9 3
6 9

输出样例

7

数据范围

对于 \(100\%\) 的数据,\(n,m \leq 100000\)

题解

考虑删除一个修改 \(i\) 会有什么影响,即本应交换的 \(a_i\)\(b_i\) 没有交换。

相当于这个调位置的人把 小 A 和 小 B 认错了,结果就是把修改做完以后,小 A 和 小 B 的原位置正好相反

因此我们可以先算出数组最终状态 \(T\) ,然后依次考虑每个修改,直到发现某一步把 \(1\)\(T_k\) 认错了。

时间复杂度 \(\mathcal{O}(m)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))

int n,m,k,a[N],b[N],p[N],x[N],y[N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m >> k;
    for(int i = 1; i <= n; i++) a[i] = i, b[i] = i;
    for(int i = 1; i <= m; i++) { cin >> x[i] >> y[i]; swap(b[x[i]], b[y[i]]); }
    for(int i = 1; i <= n; i++) p[b[i]] = i;
    for(int i = 1; i <= m; i++)
    {
        int l = a[x[i]], r = a[y[i]];
        swap(b[p[l]], b[p[r]]);
        if(b[k] == 1) return cout << i << '\n', 0;
        swap(b[p[l]], b[p[r]]); swap(a[x[i]], a[y[i]]);
    }
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录