目录
题目:
题目理解:
给你一串长度为 n 的只含0/1的数组
目标:找到最小的操作次数,把他转换成非递减数组(0在前,1在后)
一次操作:
1.选出一个非递增子序列(前面全是1,后面全是0)
2.将距离中心位置距离相等的两个项进行互换(若长度为奇数,则中心项不动)
要输出最小操作次数,以及每次操作的子序列的项数,以及下标位置。
思路:
双指针的想法, i 指针从左边开始,j指针从右边开始。
每当我左边遇到一个1,右边遇到一个0,就说明我需要将二者进行交换。
直到我的 i 指针和 j 指针相遇。这个时刻非常重要,只可能有一下两种情况:
①我刚找完一组(左1右0)然后 i++ 到的 j 位置。
②我有左边一个多出来的1,正在右边找0,但是 j-- 到了 i 的位置。
无论那种情况,在我交换之后,我的指针左侧都将是0,而指针右侧都将是1,i 和 j 重合的这个位置是1还是0都不影响满足题目非递减(0都在左边,1都在右边)的要求。
同时也恰恰证明了,我最多需要一次操作就能满足题目的非递减(0都在左边,1都在右边)要求。
所以我们只需要左指针找1,右指针找0,每找到一对就将他们的下标存到vector中,然后排个序输出就行了。(当然一对也不需要调换的话就直接输出0)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
char a[N];
int main()
{
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t; cin >> t;
while (t--)
{
vector<int>v;
int cnt = 0;
int n;
cin >> n;
cin >> a + 1;
for (int i = 1, j = n; i < j; i++)
{
if (a[i] == '0')
continue;
while (i < j && a[j] == '1')
j--;
if (i < j)
{
cnt++;
v.push_back(i);
v.push_back(j);
j--;
}
}
if (cnt == 0)
cout << "0" << '\n';
else
{
cout << 1 << '\n';
sort(v.begin(), v.end());
cout << v.size() << " ";
for (auto& i : v)
cout << i << " ";
cout << '\n';
}
}
return 0;
}