给你一叠大小(这里用直径表征)的煎饼,它们的标号是最底层的煎饼为1号,最顶层的那张为n号,即由下向上递增,给出一种操作flip(i),代表将i号煎饼及在其以上的所有煎饼形成的这一小叠颠倒顺序,比如原来是1-3-2-4-5,颠倒后为5-4-2-3-1
现在给你一叠煎饼,要求你施加一组flip操作,最终使得这叠煎饼的大小是从上往下一次递增的。输出这个序列。
其实现在回头想来,它要求你给出一种稳妥的策略,这思路并不困难:既然要求你最终达到“递增”序,说明一旦这叠煎饼输入了,我们的目的序是可以确定的,既然是递增,我们不妨就先将最大的那块放到正确的位置(即最底层),再把次大的那块放到正确的位置,以此类推,一块块达到最终位置了,整个序列也就符合要求了。
具体实现就是,对于输入的序列,考虑到规模不大,我们可以sort,得到目的序,然后走一个循环,每次循环,我们选择当前序列里没有达到目标位置的煎饼中的最大的那个,假设它是k号,我们就施加flip(k),即将这个煎饼翻到顶,然后,根据sort之后的目的序,我们知道这块煎饼应该去哪个位置,比如说是p,我们就再施加flip(p),这样,这块煎饼就达到目的位置了
当然要注意,每次施加flip都有可能影响其他的煎饼,这是因为flip操作是对一个区间作倒序。。并不是单纯的交换两块煎饼的位置,因此在操作过程中要实时模拟flip操作,这个写起来也许可以很讨巧。。然而我是感觉我写的麻烦了。。不过倒是顺利ac了
还有一坑。。输出要先输出一下原序列。。
code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cstdlib>
//#include<windows.h>
#define maxn 201314
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
const double PI=(acos(-1));
int q[200];
int p[200];
int r[200];//这三个数组用来存储原序列,目的序列,以及在模拟flip操作的时候做一个对映
int ans[500];//存放答案序列
int n;
int nmax;
int indexx=0;
int main()
{
while(scanf("%d",&q[indexx])!=EOF)
{
indexx++;
while(getchar()!='\n')
{
scanf("%d",&q[indexx++]);
}
n=indexx;
//cout<<n<<endl;
indexx=0;
for(int i=0; i<n; i++)
{
if(i<n-1){
printf("%d ",q[i]);
}
else printf("%d\n",q[i]);
p[i]=q[i];
}
sort(q,q+n);
int j=0;
int tmp;
do
{
tmp=-1;
int tmpindex=-1;
for(int i=0; i<n; i++)
{
if(p[i]>tmp&&p[i]!=q[i])
{
tmp=p[i];
tmpindex=i;
}//选择当前序列里没有达到目标位置的煎饼中的最大的那个
}
//cout<<tmp<<endl;
if(tmp!=-1)//找到了
{
if(tmpindex!=0)
{
ans[j++]=n-tmpindex;
for(int i=0; i<n; i++)
{
if(i<=tmpindex)
{
r[tmpindex-i]=p[i];
}
else
{
r[i]=p[i];
}
}
for(int i=0; i<n; i++)
{
p[i]=r[i];
}
}
for(int i=0; i<n; i++)
{
if(q[i]==tmp)
{
ans[j++]=n-i;
for(int j=0; j<n; j++)
{
if(j<=i)
{
r[i-j]=p[j];
}
else
{
r[j]=p[j];
}
}
for(int j=0; j<n; j++)
{
p[j]=r[j];
}
break;
}
}
}
}
while(tmp!=-1);//循环跳出条件是这么设置的
//cout<<j<<endl;
for(int i=0; i<j; i++)
printf("%d ",ans[i]);
printf("0\n");
}
}