B. Maximum Cost Permutation
B. Maximum Cost Permutation
https://codeforces.com/problemset/problem/2144/B
Idea: BledDest:
首先,让我们了解一下如何计算置换的代价。我声明需要排序的最小子段是端点为不在正确位置的最左和最右元素的子段。一方面,这个片段不能更短,因为这些元素必须包含在其中。另一方面,如果我们对包含所有不在正确位置的元素的子数组进行排序,那么排列肯定会按照升序进行排序——这个段之外的所有元素都已经在正确的位置上了,而段内的所有元素将按照正确的顺序排列。
现在我们需要从给定的数组中创建一个排列,使得不在正确位置的元素的最小和最大位置尽可能地远离。如果数组中只有一个 0,则只有一种方法将其转换为排列,我们只需要检查这种情况下的答案。
然而,如果数组中有多个等于 0的元素,总是有一种方法来放置缺失的元素,使得在所有先前有 0 的位置上,都有不等于这些位置的元素。要做到这一点,我们可以进行如下:首先,我们丢失的元素,尽可能多的元素匹配他们的位置(如果我们丢失的元素 i 和 i 位置数组中包含 0 , i 我们地方;剩下的元素可以放在任意),然后我们周期性转变所有放置元素(也就是说,我们第一个元素放在第二个免费的位置,第二,第三,等等)。这样,对于 0
的每个位置,都会有一个不等于该位置的元素。
因此,如果给定数组中有多个零,我们可以简单地找到所有元素与其位置匹配的最长前缀和最长后缀,假设零总是可以以不匹配其位置的方式被替换。这个前缀和后缀之间的段将是需要排序的段。
解的时间复杂度为 O(n) 。
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
vector<int> p(n);
vector<int> pos0;
vector<int> used(n);
for(int i = 0; i < n; i++)
{
cin >> p[i];
--p[i];
if(p[i] == -1)
pos0.push_back(i);
else
used[p[i]] = 1;
}
if(pos0.size() == 1)
{
int unused = 0;
for(int i = 0; i < n; i++) if(used[i] == 0) unused = i;
p[pos0[0]] = unused;
}
int l = 0, r = n - 1;
while(l < n && p[l] == l) l++;
while(r >= 0 && p[r] == r) r--;
cout << max(0, r - l + 1) << "\n";
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
for(int i = 0; i < t; i++)
solve();
}
浙公网安备 33010602011771号