第i个位置的牌是a[i],一次交换后第i个位置的牌变成a[a[i]]。

序列所有位置经过一次交换为一次交换,

已知交换m次之后的序列,求原先序列

思路:


给出a[i]为4 7 5 6 1 2 3

进行一次变换    

1 2 3 4 5 6 7    4 7 5 6 1 2 3          1 2 3 4 5 6 7

                     *                           =

4 7 5 6 1 2 3    6 3 1 2 4 7 5           6 3 1 2 4 7 5

进行二次变换

1 2 3 4 5 6 7        6 3 1 2 4 7 5        1 2 3 4 5 6 7

                         *                        =

6 3 1 2 4 7 5       7 1 6 3 2 5 4         7 1 6 3 2 5 4

进行三次变换

1 2 3 4 5 6 7         7 1 6 3 2 5 4       1 2 3 4 5 6 7

                       *                          =

7 1 6 3 2 5 4         4 7 5 6 1 2 3       4 7 5 6 1 2 3

 

则进行三次变换后得到4 7 5 6 1 2 3

原序列在第三次变换的时候出现了循环

考虑一般情况。

因为原序列为1~N个不同的数,则序列能构成至少一个置换群,

则经过多次变换后肯定

会出现循环,

现在我们求出置换的循环节,已知新的序列,和进行交换的次数,

则再进行res - s % res

次交换即可得到原序列。

//res为循环节,s为给出的变换次数



#include <stdio.h>
#include <string.h>

int Array[1010],ArrayA[1010],ArrayB[1010];

void GetNext(int n)
{
for(int i = 1; i <= n; i++)
ArrayB[i] = ArrayA[ArrayA[i]];
for(int i = 1; i <= n; i++)
ArrayA[i] = ArrayB[i];
}

bool IsSame(int n)
{
for(int i = 1; i <= n; i++)
if(ArrayB[i]!=Array[i])
return false;
return true;
}
int main()
{
int n,s;
while(~scanf("%d%d",&n,&s))
{
for(int i = 1; i <= n; i++)
{
scanf("%d",&Array[i]);
ArrayA[i] = Array[i];
}
int res;
for(res = 1;;res++)
{
GetNext(n);
if(IsSame(n))
break;
}
int m = res - s % res;
int num = 0;
while(num < m)
{
GetNext(n);
num++;
}
for(int i = 1; i <= n; i++)
printf("%d\n",ArrayB[i]);
}
return 0;
}