思路:构造。
考虑每次操作都对一个数排到对应的位置,这样最多操作 n n n次。
当 n n n为偶数时,按照 n , 1 , n − 1 , 2 … n,1,n-1,2\dots n,1,n−1,2…的顺序操作。
当 n n n为奇数时,按照 1 , n , 2 , n − 1 … 1,n,2,n-1\dots 1,n,2,n−1…的顺序操作。
这样根据翻转和奇偶性,最后之前排好的位置仍然是排好的。
设一开始未排好的区间为 [ l , r ] = [ 1 , n ] [l,r]=[1,n] [l,r]=[1,n],每次排好一个数就减小区间范围。
比如排好了数 l l l,则区间变为 [ l + 1 , r ] [l+1,r] [l+1,r],排好了 r r r区间就变为了 [ l , r − 1 ] [l,r-1] [l,r−1]。
直到排好所有数为止。
注意要去除掉分块的个数小于 2 2 2的操作,因为题目要求每次操作最少将数组分为两块。
举个例子:
n
=
4
。
n=4。
n=4。
初始序列为:
3
,
1
,
2
,
4
3,1,2,4
3,1,2,4
1.
[
1
,
4
]
[1,4]
[1,4]操作的数为:
4
4
4,分块为:
3
,
1
3,1
3,1。
序列变为:
4
,
3
,
1
,
2
4,3,1,2
4,3,1,2。
2.
[
1
,
3
]
[1,3]
[1,3]操作的数为:
1
1
1,分块为:
1
,
1
,
2
1,1,2
1,1,2。
序列变为:
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4。
3.
[
2
,
3
]
[2,3]
[2,3](注意这里其实已经排好了,但是我们按照构造的思路会对每个数进行操作).
操作的数为;
3
3
3,分块:
1
,
1
,
1
,
1
1,1,1,1
1,1,1,1。
序列变为:
4
,
3
,
2
,
1
4,3,2,1
4,3,2,1。
4.
[
2
,
2
]
[2,2]
[2,2],操作的数为:
2
2
2,分块:
1
,
1
,
1
,
1
1,1,1,1
1,1,1,1。
序列变为:
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4。
具体看代码。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=55,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define reg register
#define PII pair<int,int>
#define pb push_back
int n,a[N],b[N];
vector<int>ans[N];
void fun(int tot){
int k=n,cnt=0;
for(int i=ans[tot].size()-1;~i;i--){
for(int j=k-ans[tot][i]+1;j<=k;j++)
b[++cnt]=a[j];
k-=ans[tot][i];
}
for(int i=1;i<=n;i++) a[i]=b[i];
//printf("\n-------------\n");
}
int solve(){
int l=1,r=n,flag=n%2,tot=0,k;
while(l<=r){
k=flag?l:r;
ans[tot].clear();
for(int i=1;i<=n;i++){
if(a[i]<l||a[i]>r) ans[tot].pb(1);
else {
int j=i,pos;
for(;j<=n&&a[j]>=l&&a[j]<=r;j++)
if(a[j]==k) pos=j;
if(pos!=i) ans[tot].pb(pos-i);
ans[tot].pb(j-pos);
i=j-1;
}
}
if(flag) l++;
else r--;
flag^=1;
if(ans[tot].size()>1){
fun(tot);
tot++;
}
}
return tot;
}
int main(){
scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int tot=solve();
printf("%d\n",tot);
for(int i=0;i<tot;i++){
printf("%d",ans[i].size());
for(auto j:ans[i]) printf(" %d",j);
printf("\n");
}
return 0;
}