Twist the Permutation 数列的轮换题 Codeforces 776 div3


这是一道比较经典的将数列中的数字轮换的题目,我们先看题干:

题干分析:先浅浅地分析一下题目是要我们干什么,我们会默认有一个已经升序排序地1~n的排列,然后我们会给定一个新排列是在原有排列的基础上进行operation得到的,那么我们来看看这个operation是什么:

  这个operation是对每一个位置i上进行操作的,就是对前i个数向右移动一位,并且在第i位上可以执行的operation次数是无穷的;

  接下来,我们要发现题干叫我们求的是什么,他问我们能不能从初始序列经过尽可能小的operation次数到达给定的序列,我们就是要让这个数尽可能地小;

  然后我们是要怎么解决这道题呢?首先我们可以发现,我是根据i的顺序从小到大逐渐把前面的顺序逐渐打乱的,说明在d[n]之前,n这个最大的数字肯定是没有动过,所以d[n]是多少纯粹是根据n被移动到了哪里决定的,因为其他的不影响n的位置,所以可根据n的位置反推出d[n],同理我们可以反推出d[n-1]……以此类推!

  最后我们再来考虑一下是怎么得到d[n]的,我们通过倒着循环i,当找到n的位置为j之后,我们令ind(index)等于j,我们就知道这里换转了(ind+1)%i次

所以我们就把所有的数全部换回去,所以我们循环1~i,找到他们本来的位置换回去,这样的话,d[n]就完成了,我只要接下来完成同样的循环就好了!

  因为我需要找回n个数,每次找回一个数的时间复杂度是O(n)的,所以这个算法的时间复杂度是O(n^2)

   接下来是代码:

#include

#define maxn 2100

 

using namespace std;

int q[maxn],n,b[maxn],ans[maxn];

 

int main()

{

int t;

cin >> t;

while(t--){

int n;

cin >> n;

for(int i = 0;i> q[i];

for(int i = n;i>=1;i--){

int ind  = 0;

for(int j = 0;j

for(int j = 0;j

for(int j = 0;j

ans[i-1] = i!=1 ? (1+ind)%i : 0;

}

for(int i = 0;i

cout << '\n';

}

return 0;

}