这是问题的链接:https : //ioi2019.az/source/Tasks/Day1/Shoes/NGA.pdf
这是有关问题状态的简要说明:
您将得到一个1到n≤1e5范围内的整数n,该整数n表示数组内部的正整数数量,以及数组中的负整数数量(因此,数组的总大小为2n)。
该问题希望您找到数组中需要的最小交换数,以使数字的负值与该负数的绝对值彼此相邻(例如-x在x的右侧)
例:
n = 2;
输入的数组= {2,1,-1,-2}
最小操作数为四:
2,1,-1,-2:0交换
2,-1,1,-2:1交换(交换1和-1)
2,-1,-2,1:2个交换(交换1和-2)
2,-2,-1,1:3个交换(交换-1和-2)
-2,2,-1,1:4个交换(交换2和-2)
最终答案将是四个。
另一个例子:
输入的数组= {-2,2,2,-2,-2,2}
最小掉期为1。因为我们可以交换索引2和3的元素。
最终数组:{-2,2,-2,2,-2,2}
当做这个问题时,我得到了错误的答案,我决定在git hub上查看某人的源代码。
这是源代码:
#include "shoes.h"
#include <bits/stdc++.h>
#define sz(v) ((int)(v).size())
using namespace std;
using lint = long long;
using pi = pair<int, int>;
const int MAXN = 200005;
struct bit{
int tree[MAXN];
void add(int x, int v){
for(int i=x; i<MAXN; i+=i&-i) tree[i] += v;
}
int query(int x){
int ret = 0;
for(int i=x; i; i-=i&-i) ret += tree[i];
return ret;
}
}bit;
lint count_swaps(vector<int> s) {
int n = sz(s) / 2;
lint ret = 0;
vector<pi> v;
vector<pi> ord[MAXN];
for(int i=0; i<sz(s); i++){
ord[abs(s[i])].emplace_back(s[i], i);
}
for(int i=1; i<=n; i++){
sort(ord[i].begin(), ord[i].end());
for(int j=0; j<sz(ord[i])/2; j++){
int l = ord[i][j].second;
int r = ord[i][j + sz(ord[i])/2].second; //confusion starts here all the way to the buttom
if(l > r){
swap(l, r);
ret++;
}
v.emplace_back(l + 1, r + 1);
}
}
for(int i=1; i<=2*n; i++) bit.add(i, 1);
sort(v.begin(), v.end());
for(auto &i : v){
ret += bit.query(i.second - 1) - bit.query(i.first);
bit.add(i.first, -1);
bit.add(i.second, -1);
}
return ret;
}
但是,我认为我不太了解这段代码。
我知道在BIT中添加和查询的功能是什么,我一直困惑到底在哪里对代码进行注释。我不明白它的作用和目的。
有人可以浏览这段代码在做什么吗?或就如何正确有效地解决此问题提供任何建议(甚至可能是您的解决方案?)。谢谢。
int r = ord[i][j + sz(ord[i])/2].second;
我们已经将向量中的一个鞋子大小的元组进行了排序<size, idx>
,这意味着该大小的所有负数都占据的前半部分ord[i]
,而所有正数都位于下半部分。
if (l > r){
swap(l, r);
ret++;
}
在对大小进行排序之后,每个对应对的索引可能不会在负数之前与负数排序。其中每一个都需要交换。
v.emplace_back(l + 1, r + 1);
在v
我们的间隔中插入一双相应尺码的鞋子i
。
for(int i=1; i<=2*n; i++) bit.add(i, 1);
sort(v.begin(), v.end());
在我们的总和树中为鞋子的每个索引位置添加值1。排序鞋子间隔。
for(auto &i : v){
ret += bit.query(i.second - 1) - bit.query(i.first);
对于中的每双鞋v
,所需的交换数是它们之间剩余的鞋数,以段的总和表示。
bit.add(i.first, -1);
bit.add(i.second, -1);
从树上卸下这双鞋,这样一来,新的细分金额就不会包括在内。我们可以这样做,因为鞋子间隔是从左到右进行处理的,这意味着没有一双“内”的鞋子要在外一双鞋子之前进行处理。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句