时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0 A1……AN-1)变换为(AN-M …… AN-1 A0 A1……AN-M-1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

输入格式:每个输入包含一个测试用例,第1行输入N ( 1<=N<=100)、M(M>=0);第2行输入N个整数,之间用空格分隔。

输出格式:在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

输入样例:
6 2
1 2 3 4 5 6
输出样例:
5 6 1 2 3 4

思想:其实思想还是比较简单的,就是把数组两端相应的数据交换位置,然后在子序列里进行同样的操作,这样说可能有点笼统,举个例子:(1 2 3 4 5 6)——>5 6 (3 4 1 2)——>5 6 1 2 (3 4),还有就是(1 2 3 4 5 6 7)——> 6 7 (3 4 5 1 2)——>6 7 1 2 (5 3 4)——>6 7 1 2 (4 3) 5——>6 7 1 2 (3) 4 5,右移次数都是2,()内是子序列,每次针对子序列里交换数据的个数等于min(N-M,M),并调整相应的low跟high(子序列的起始和末尾),而flip和f2布尔变量就是针对这个而设的,还要考虑递归的终止条件,多在纸上走几个例子就能加深理解了。当然还有最基本的方法就是右移多少个就利用直接插入排序往前插几个但这样移动次数可能较多并且题目并没有说数组元素有序,那么得添加一些信息,比如初始时下标大的元素就大不管它实际上是什么。还有一种耍赖的方法,就是直接改变输出,先输出后M位再输出前面的。补充:王道单科书上例题给出这样的解答思想:循环左移本质是将ab变成ba,a就是那个被左移的部分,先将a和b分别逆置,成为a^-1和b^-1,然后整体逆置(a^-1*b^-1)^-1==ba,本人觉得十分好,特意添加上去。

#include <iostream>
using namespace std;
bool flip, f2= true;
void swapgroup(int*A,int &M,int &low,int &high)
{
flip=!flip;
int N =high-low+1;
M%=N;
if(M ==0)return;
if(high-low<=1)
{

if(flip)
{
int temp =*(A+low);
*(A+low) = *(A+high);
*(A+high) = temp;
}


return;
}
int delta = N-M, temp;
if(M>delta)
{
for(int i=0; i<delta; i++)
{
temp = *(A+i+low);
*(A+low+i) = *(A+high-N+M+1+i);
*(A+high-N+M+1+i) = temp;
}
if(f2)
{
high-=delta;
f2 = false;
}
else
{
low +=delta;
f2 = true;
}
swapgroup(A,delta,low,high);

}
else
{
for(int i=0; i<M; i++)
{
temp = *(A+i+low);
*(A+low+i) = *(A+high-M+1+i);
*(A+high-M+1+i) = temp;
}
if(f2)
low+=M;
else high -=M;
swapgroup(A,M,low,high);

}


}

int main()
{
int N,M;
cin>>N>>M;
M%=N;
flip = (N-((N-M)<M?(N-M):M)+1)%2 ;
int *A = new int[N];
for(int i=0; i<N; i++)
{
cin>>A[i];
}
int L = 0,H = N - 1;
swapgroup(A,M,L,H);

for(int i=0; i<N; i++)
{
cout<<A[i];
if(i!=N-1)
cout<<" ";
}
return 0;
}