题目传送门:Luogu UVA120
经典的模拟题
我们现在有一个乱序数组,现在我们可以对它进行一个操作,即翻转( ext{1-k})间所有数,现在要求输出一个使乱序数组变成一个有序数组的可行(k_i,i in [1,n])
现排序后数组为( ext{goal}),当前数组为( ext{a})
翻转:
我们现在想模拟翻转( ext{1-k})间所有数,我们需要一个函数来解决这个问题
void work(int x) {
for(int l = 1, r = x; l < r; l ++, r --) //l属于1 ~ (x >> 1), r 属于(x >> 1) + 1 ~ x,此时我们只需要交换a[l],a[r]的位置即可实现翻转
swap(a[l], a[r]);
return;
}
求解:我们需要找到这些( ext{k}),我们有这么个想法:
- 1~tot枚举一遍,如果
a[tail] = goal[tail]
,那么这后面的数都是有序的了,那就不用考虑,直接tail --;
- 如果
a[tail] != goal[tail]
,那么我们考虑另一种情况:如果找到的i对应a[i] = goal[tail]
不是第一个,那么我们便需要将( ext{1~i})翻转,输出注意是tot - i + 1
,但是不论i是否等于1,我们都需要将1~tail
翻转过来,然后输出tot - tail + 1
while(!check(tot))//check是用来检查当前的数组是否和目标数组一样
for(int i = 1; i <= tot; i ++)
if(a[tail] == goal[tail]) tail --;
else if(a[i] == goal[tail]) {
if(i != 1) work(i), printf("%d ", tot - i + 1);
work(tail);
printf("%d ", tot - tail + 1);
tail --;
break;
}
code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[100], goal[100];
string s;
void work(int x) {
for(int l = 1, r = x; l < r; l ++, r --) swap(a[l], a[r]);
return;
}
bool check(int tot) {
for(int i = 1; i <= tot; i ++) if(a[i] != goal[i]) return 0;
return 1;
}
int main() {
while(getline(cin, s)) {
memset(a, 0, sizeof a);
memset(goal, 0, sizeof goal);
int len = s.length(), num = 0, tot = 0;
for(int i = 0; i < len; i ++)
if(s[i] != ' ') num = num * 10 + s[i] - 48;
else if(s[i] == ' ' || i == len - 1) {
printf("%d ", num), tot ++, goal[tot] = a[tot] = num, num = 0;
puts("");
sort(goal + 1, goal + tot + 1);
int tail = tot;
while(!check(tot))
for(int i = 1; i <= tot; i ++)
if(a[tail] == goal[tail]) tail --;
else if(a[i] == goal[tail]) {
if(i != 1) work(i), printf("%d ", tot - i + 1);
work(tail);
printf("%d ", tot - tail + 1);
tail --;
break;
}
puts("0");
}
return 0;
}