持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。
D. Permutation Addicts
题目
给出一个1到n的整数的排列组合a1,a2,...,an,以及一个0≤k≤n的阈值k,你计算一个序列b1,b2,...,bn如下。
对于每个1≤i≤n的递增顺序,让x=ai。
如果x≤k,将bx设为aj>k的最后一个元素aj(1≤j<i)。如果不存在这样的元素aj,设bx=n+1。 如果x>k,将bx设为aj≤k的最后一个元素aj(1≤j<i)。如果不存在这样的元素aj,设置bx=0。 不幸的是,在序列b1,b2,...,bn被完全计算后,排列组合a1,a2,...,an和阈值k被丢弃了。
现在你只有序列b1,b2,...,bn。你的任务是找到任何可能的排列组合a1,a2,...,an和阈值k来产生序列b1,b2,...,bn。可以保证至少有一对排列组合a1,a2,...,an和阈值k可以产生序列b1,b2,...,bn。
从1到n的整数排列是一个长度为n的序列,其中正好包含所有从1到n的整数一次。
题目大意就是给我们一个B数组让我们还原除原来的A数组和 对于k我们只需要统计 的数量就行了 然后我们根据bi 和 i建图
从样例一和样例二的图中我们可以发现以n+1为根的点优先向没有子节点的根节点去遍历
得出来的答案就是原来的a数组
最后放上总代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
using ll = long long;
#define int long long
#define endl '\n'
#define pb push_back
#define NO cout << "NO" << endl;
#define YES cout << "YES" << endl;
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,n) for(int i = 1; i <= n; i++)
typedef pair<int,int> PII;
const int N = 2e5 + 10;
int b[N];
vector<int> v[N];
vector<int> ans;
void dfs(int x) {
ans.pb(x);
int son = -1;
for(auto u : v[x]) {
if(v[u].size() == 0) dfs(u);
else son = u;
}
if(son != -1) dfs(son);
}
void solve()
{
int n; cin >> n;
int k = 0;
int st = 0;
for(int i = 0; i <= n + 1; i++) v[i].clear();
rep(i,n) {
cin >> b[i];
v[b[i]].pb(i);
if(b[i] == n + 1) st = b[i];
if(b[i] > i) k ++;
}
ans.clear();
dfs(st);
cout << k << endl;
for(int i = 1; i < ans.size(); i++) cout << ans[i] << ' ';
cout << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;cin >> T;
while ( T -- )
solve();
return 0;
}