CF1701D Permutation Restoration
题意简述
Monocarp 有一个由 个数字 组成的排列 。
然后 Monocarp 计算出了一个由 个数字组成的数列 ,满足 。
现在 Monocarp 丢掉了排列 ,他希望你可以通过数列 倒推出排列 ,如果有多个答案,给出任意一个即可,数据保证有解。
多测,
问题分析
由于有 ,可以得到 ,即 。
枚举排列 中每个数,假设现在枚举到 。对于每个 ,存在一些线段 ,满足 。
从贪心的角度来说,对于这些线段,我们选择右端点最小的线段,为其他空留下更多的选择空间。
考虑类似于尺取的方法,从 枚举到 ,当枚举到 的时候,将所有以 为左端点的线段加入到一个以右端点为排序关键字的优先队列中,每次选取最小的即可。
代码实现
#include<bits/stdc++.h> using namespace std; typedef long long LL; template < typename Tp > void read(Tp &x) { x = 0; int fh = 1; char ch = 1; while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if(ch == '-') fh = -1, ch = getchar(); while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= fh; } const int maxn = 500000 + 7; int T, n, b[maxn]; void Init(void) { read(T); } pair <int, pair<int, int> > pr[maxn]; priority_queue < pair<int, int> > Q; int ans[maxn]; void Work(void) { while(T--) { for(int i = 1; i <= n; i++) { ans[i] = 0; pr[i].first = pr[i].second.first = pr[i].second.second = 0; } read(n); // memset(ans, 0, sizeof(ans)); // while(!Q.empty()) Q.pop(); // memset(pr, 0, sizeof(pr)); for(int i = 1; i <= n; i++) { read(b[i]); pr[i].first = i / (b[i] + 1) + 1; if(b[i] == 0) pr[i].second.first = n; else pr[i].second.first = i / b[i]; pr[i].second.second = i; } sort(pr + 1, pr + n + 1); int cnt = 0; for(int i = 1; i <= n; i++) { while(cnt <= n && pr[cnt + 1].first == i) { Q.push(make_pair(-pr[cnt + 1].second.first, pr[cnt + 1].second.second)); cnt++; } int id = Q.top().second; Q.pop(); ans[id] = i; } for(int i = 1; i <= n; i++) { printf("%d%c", ans[i], " \n"[i == n]); } } } int main(void) { Init(); Work(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)