当前位置:网站首页>2019浙江省赛C-错排问题,贪心
2019浙江省赛C-错排问题,贪心
2022-07-25 15:23:00 【塔子哥来了】
题目大意:
给你一个序列,让你找出一种字典序最小的错排。
题目思路:
1.将这个问题拓展一下:
给两个序列(不一定全等)。找字典序最小的错排。
2.错排存在的充要条件为:两个序列的和中出现次数最多的数 不超过 序列总长.(鸽巢定理)
3.依靠条件2,我们自然可以直接贪心的从小往大的填数,同时保证任意时刻,条件2成立即可(剩下的数最多出现次数不超过剩下的位置).
那么填数分两个阶段,第一个阶段贪心的填最小值和次小值。第二阶段到达条件2的临界条件。
代码有注释:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vl vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
int a[maxn] , b[maxn] , n;
set<int> s;
multiset<int> ms; // 动态维护总出现次数
unordered_map<int,int> Tcnt , cnt; // 总体每个数出现次数和下面一列
void del (int x , int down){
auto g = ms.find(Tcnt[x]);
ms.erase(g);
Tcnt[x]--;
if (Tcnt[x] == 0) Tcnt.erase(x);
else ms.insert(Tcnt[x]);
if (down)
cnt[x]--;
if (cnt[x] == 0){
s.erase(x);
cnt.erase(x);
}
}
int c[maxn];
void imp (int x){
vi mx;
for (auto & g : Tcnt)
if (n - x + 1 == g.second) mx.push_back(g.first);
if (mx.size() == 1){
vi ot;
for (auto & g : cnt)
if (g.first != mx[0])
for (int i = 1 ; i <= g.second ; i++)
ot.push_back(g.first);
sort(ot.begin(),ot.end());
reverse(ot.begin(),ot.end());
for (int i = x ; i <= n ; i++){
if (a[i] == mx[0]) {
b[i] = ot.back();
ot.pop_back();
}else {
b[i] = mx[0];
}
}
}else {
// 真 唯一方案
for (int i = x ; i <= n ; i++){
if (a[i] == mx[0]) b[i] = mx[1];
else b[i] = mx[0];
}
}
return ;
}
int main()
{
ios::sync_with_stdio(false);
int t; cin >> t;
while (t--){
s.clear();
ms.clear();
Tcnt.clear();
cnt.clear();
cin >> n;
for (int i = 1 ; i <= n ; i++){
cin >> a[i];
s.insert(a[i]);
cnt[a[i]]++;
Tcnt[a[i]] += 2;
}
// 判断局面合法
bool ok = true;
for (auto & g : Tcnt){
if (g.second > n) {
ok = false;
break;
}
ms.insert(g.second);
}
if (!ok){
cout << "Impossible" << endl;
continue;
}
/* 放的时候有三种情况: 0.若 上下两行的数的并 最多出现次数 = 剩下位置的个数 ,这种局面直接处理 1.若当前对位不是最小值,就放最小值. 2.否则放次小值 要维护: 1.当前元素最小值,次小值 2.每个数出现次数以及出现次数的最大值 */
for (int i = 1 ; i <= n ; i++){
int mxcnt = *ms.rbegin();
if (mxcnt == n - i + 1){
imp(i);
break;
}
int miv[4], d = 0;
for (auto & g : s){
miv[++d] = g;
if (d == 2) break;
}
if (a[i] != miv[1]) b[i] = miv[1];
else b[i] = miv[2];
del(a[i] , false);
del(b[i] , true);
}
for (int i = 1 ; i <= n ; i++){
cout << b[i];
if (i == n) cout << endl;
else cout << " ";
}
}
return 0;
}
边栏推荐
猜你喜欢

图论及概念

Image cropper example

VMware Workstation fails to start VMware authorization service when opening virtual machine

小波变换--dwt2 与wavedec2

ML - 语音 - 传统语音模型

为什么PrepareStatement性能更好更安全?

Application of object detection based on OpenCV and yolov3

获取键盘按下的键位对应ask码

带你创建你的第一个C#程序(建议收藏)

Outline and box shadow to achieve the highlight effect of contour fillet
随机推荐
Flex 布局
Once spark reported an error: failed to allocate a page (67108864 bytes), try again
The difference between Apple buy in and apple pay
分布式原理 - 什么是分布式系统
Tasks, micro tasks, queues and scheduling (animation shows each step of the call)
记一次Spark报错:Failed to allocate a page (67108864 bytes), try again.
记一次Yarn Required executor memeory is above the max threshold(8192MB) of this cluster!
Spark judges that DF is empty
spark分区算子partitionBy、coalesce、repartition
matlab--CVX优化工具包安装
Spark 内存管理机制 新版
谷歌云盘如何关联Google Colab
如何更新更新数据库中的json值?
反射-笔记
Rediscluster setup and capacity expansion
How to solve the problem of scanf compilation error in Visual Studio
你准备好脱离“内卷化怪圈”了吗?
Node learning
分布式 | 实战:将业务从 MyCAT 平滑迁移到 dble
Word 样式模板复制到另一文档