[CF1333D] Challenges in school №41 - 逆序对,冒泡排序
Description
给定一个含 L,R 的序列,一次操作可以将若干个相邻 R,L 对翻转,问能否通过恰好 (k) 轮操作完成整个翻转过程。
Solution
题目给出的交换方法很容易想到冒泡排序。
最大答案等于逆序对数,这个可以 (O(n)) 求出,最小答案不太好求。
每次先统计出逆序对数 x,然后暴力去做一轮冒泡,但是冒泡的次数上限是 x-k。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, k;
int calc_n_inv(vector<int> a)
{
int ans = 0;
for (int i = 0; i < n; i++)
for (int j = n - 1; j > 0; j--)
if (a[j - 1] > a[j])
swap(a[j], a[j - 1]), ++ans, j--;
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> k;
vector<int> a(n);
string str;
cin >> str;
for (int i = 0; i < n; i++)
{
char t;
t = str[i];
a[i] = t == 'L' ? 0 : 1;
}
int x = calc_n_inv(a);
vector<vector<int>> record;
int cnt = 0;
while (x && k && x > k)
{
++cnt;
if (cnt > 2 * n)
break;
k--;
vector<int> cur;
for (int i = 1; i < n && x > k; i++)
{
if (a[i] < a[i - 1])
{
swap(a[i], a[i - 1]);
cur.push_back(i);
i++;
x--;
}
}
if (cur.size() == 0)
{
cout << -1;
return 0;
}
record.push_back(cur);
}
while (x && x == k)
{
for (int i = 1; i < n; i++)
{
if (a[i] < a[i - 1])
{
swap(a[i], a[i - 1]);
record.push_back(vector<int>(1, i));
i++;
x--;
k--;
}
}
}
stringstream ss;
if (k || x)
{
ss << -1 << endl;
}
else
{
for (const auto &vec : record)
{
ss << vec.size() << " ";
for (const auto &i : vec)
ss << i << " ";
ss << endl;
}
}
cout << ss.str();
}
``