题目大意:
给你一副牌,最开始按照第 (i) 个位置是 (c[i]) 的一个排列,你可以进行一种操作:
- 选择一个大小 (k) ,把这 (n) 张牌分成 (k) 个部分,分别是 (D1,D2,...,Dk)
- 然后这 (k) 个部分,翻转(每个部分内部的顺序不变),所以就是 (Dk,Dk-1,...,D1)
问经过多少操作,这 (n) 张牌变成有序的,经验证最多 (n) 此操作一定可以。
所以请你输出一个答案, (0<=q<=n) ,然后输出每一次操作是怎么分的,不要求操作数最少。
(n<=52)
题解:
一个很简单的模拟题,稍微想想就应该可以想出,但是写起来不是那么简单。
之前写过类似的题目,用结构体来处理。
思路:
- 我每次操作只需要找到一个就可以了,就是让一部分和一部分连接就可以了
- 每一个部分是连续的一串数。
- 所以对于第 (i) 个部分,我只要判断这个 r +1 的位置是不是在前面,如果是,那么进行一次操作
- 进行完操作之后,更新 (c[i]) ,更新结构体
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
typedef long long ll;
struct node{
int l,r,id;
node(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
}e[maxn];
int c[maxn],pre[maxn],now,cnt;
stack<int>sta[maxn];
void getE(int n){
now = 1;
e[1] = node(c[1],c[1],1);
for(int i=2;i<=n;i++){
if(c[i]==e[now].r+1) e[now].r ++;
else e[++now] = node(c[i],c[i],i);
}
}
int getC(int l,int r){
// printf("getC: l = %d r = %d
",l,r);
int ans = 0;
for(int k=l;k<=r;k++) {
for (int h = e[k].l; h <= e[k].r; h++) {
c[++cnt] = h;
ans++;
}
}
return ans;
}
void debug(int n){
for(int i=1;i<=n;i++){
printf("c[%d]=%d ",i,c[i]);
}
printf("
");
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&c[i]);
}
int pos = 0;
for(int i=1;i<=n;i++){
getE(n),cnt = 0;
if(now==1) break;
memset(pre,-1,sizeof(pre));
for(int j=1;j<=now;j++){
// printf("i = %d j = %d now = %d
",i,j,now);
if(pre[e[j].r+1]!=-1){
int u = pre[e[j].r+1],v = j;
++pos;
int cur = getC(v+1,now);
// printf("1 v = %d cur = %d
",v,cur);
if(cur) sta[pos].push(cur);
cur = getC(v,v);
// printf("2 v = %d cur = %d
",v,cur);
if(cur) sta[pos].push(cur);
cur = getC(u,v-1);
// printf("3 v = %d cur = %d
",v,cur);
if(cur) sta[pos].push(cur);
cur = getC(1,u-1);
// printf("4 v = %d cur = %d
",v,cur);
if(cur) sta[pos].push(cur);
break;
}
pre[e[j].l] = j;
}
// debug(n);
}
printf("%d
",pos);
for(int i=1;i<=pos;i++){
printf("%d ",sta[i].size());
while(!sta[i].empty()){
printf("%d",sta[i].top());sta[i].pop();
if(sta[i].empty()) printf("
");
else printf(" ");
}
}
return 0;
}