题目的意思是将这n张牌修改成一个顺子,求最小的操作次数
修改后的顺子一定是[left, left + 1, left + 2, ... , right],其中right - left + 1 = n, 也就是长度为n
那么最优的方法就是依次枚举每一个a[i]为左边界left,然后看有多少个元素在[a[i], a[i] + n - 1]
所以首先得对a[]数组进行从小到大的排序并且去重
sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end());然后依次枚举每一个a[i]:
ans表示的是最小需要操作的次数,初始化n,表示最坏情况将n个数全部操作1次
以a[i]为左边界,那么有边界就是a[i] + n - 1, 用upper_bound来找到第一个大于a[i] + n - 1的位置,那么next_pos - i 表示在区间[a[i], a[i] + n - 1]包含了多少个a[]中的元素,这些元素在区间中那么就 不需要修改,所以n - sum就表示需要修改的数目,以此来更新操作次数的最小值即ans
pos表示存储的左边界
int ans = n, pos = 0;
for(int i = 0; i < (int)a.size(); i ++){
int next_pos = upper_bound(a.begin(), a.end(), a[i] + n - 1) - a.begin();
int sum = next_pos - i;
if(n - sum < ans){
ans = n - sum;
pos = a[i];
}
}
cout << ans << endl;
剩下的就是求哪些元素需要操作以及操作到哪个位置,并不需要求具体哪些元素需要操作,只需要求需要操作的位置以及操作后的位置
既然现在左边界已经有了,那么我们就可以得知哪些元素在这个里面,但是不知道这些元素在原来a[]数组里面的位置,所以还得用map一开始存储数组元素的下标位置
int n; cin >> n;
vector<int> a(n);
map<int, int> ma;
for(int i = 0; i < n; i ++){
cin >> a[i];
ma[a[i]] = i;
}
煎蛋来说:有两个数组
第一个数组是一开始的a数组,第二个数组是题目需要的顺子数组
现在我们确定了a[i]为顺子的左边界
vis1数组表示的是顺子数组里面的填充情况,如果为1表示该位置不需要操作,a数组里面存在一个值直接放在这个位置就可以了,如果为0则表示需要操作
vis2数组表示原来的a数组下标的使用情况,如果为1则表示该位置的元素直接放在顺子数组里面了,而为0则表示这个值不在顺子数组里面,我需要对其进行操作
pos是顺子的左边界即之前的a[i], now_num = pos + i 则是顺子数组里面的每一个元素
如果ma.count(now_num)则表示now_num既在原来的a数组中存在也在顺子数组中存在.....
vector<int> vis1(n + 1), vis2(n + 1);
for(int i = 0; i < n; i ++){
int now_num = pos + i;
if(ma.count(now_num)){
vis1[i] = 1;
vis2[ma[now_num]] = 1;
}
}
最后就是输出操作的位置:
int now = pos;
for(int i = 0; i < n; i ++){
while(vis1[now - pos]) now ++;
if(vis2[i]) continue;
else cout << i + 1 << " " << now ++ << endl;
}
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
signed main(){
HelloWorld;
int n; cin >> n;
vector<int> a(n);
map<int, int> ma;
for(int i = 0; i < n; i ++){
cin >> a[i];
ma[a[i]] = i;
}
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
int ans = n, pos = 0;
for(int i = 0; i < (int)a.size(); i ++){
int next_pos = upper_bound(a.begin(), a.end(), a[i] + n - 1) - a.begin();
int sum = next_pos - i;
if(n - sum < ans){
ans = n - sum;
pos = a[i];
}
}
cout << ans << endl;
vector<int> vis1(n + 1), vis2(n + 1);
for(int i = 0; i < n; i ++){
int now_num = pos + i;
if(ma.count(now_num)){
vis1[i] = 1;
vis2[ma[now_num]] = 1;
}
}
int now = pos;
for(int i = 0; i < n; i ++){
while(vis1[now - pos]) now ++;
if(vis2[i]) continue;
else cout << i + 1 << " " << now ++ << endl;
}
return 0;
}



京公网安备 11010502036488号