595 字
3 分钟
ABC367 E - Permute K times 题解
Atcoder Beginner Contest 367 E - Permute K times
题目翻译
问题陈述
给定一个长度为 的序列 ,其中每个元素介于 和 之间(含两个元素),以及一个长度为 的序列 。
打印对 执行以下操作 次的结果。
- 将 替换为 ,使得 。
数据范围
- 所有输入值均为整数。
解题思路
对于这类进行单一重复操作且数据范围异常大 的题目,我们可以考虑倍增。
以 为例。
原输入为:
7 35 2 6 3 1 4 61 2 3 5 7 9 11我们先模拟 次操作:
7 2 9 3 1 5 9在上面的基础上再模拟 次:
1 2 5 9 7 3 5这样,我们就可以将两步合并为一步,跳过第 次的模拟,只需要 次操作即可获得我们需要的数组。
继续进行合并, 步、 步、 步、 步…… 次操作便能很快完成。
如果 为奇数,需要先操作一次将其转换为偶数再进行倍增。
时间复杂度:。
倍增思想在快速幂算法、求 (最近公共祖先) 中均有应用,可以大大降低重复操作的时间复杂度。
此外,本题还有时间复杂度为 的图论做法,可自行阅读官方题解。
完整代码
#include<bits/stdc++.h>using namespace std;#define int long long#define endl '\n'int n, k;
signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); //cin cout 优化 cin >> n >> k; vector<int> x(n); vector<int> y(n); for(int i = 0; i < n; i++){ cin >> x[i]; x[i]--; //下标从0开始 } iota(y.begin(), y.end(), 0); //将 y 赋值为0 ~ n-1 while(k > 0){ if(k % 2 == 1){ //k为奇数则操作一次 for(int i = 0; i < n; i++){ y[i] = x[y[i]]; } }
vector<int> tmp(n); for(int i = 0; i < n; i++){ tmp[i] = x[x[i]]; } x = move(tmp); //将tmp直接覆盖到x上,时间复杂度 O(1) k /= 2; //倍增 } vector<int> a(n); vector<int> b(n); for(int i = 0; i < n; i++){ cin >> a[i]; } for(int i = 0; i < n; i++){ b[i] = a[y[i]]; cout << b[i] << " \n"[i == N - 1]; } return 0;}参考
Submission #56848064 - jiangly
ABC367 E - Permute K times 题解
https://darkmodest.github.io/posts/solutions/abc367e/