1. 程式人生 > 其它 >Twist the Permutation 數列的輪換題 Codeforces 776 div3

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<bits/stdc++.h>

#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<n;i++) cin >> q[i];

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

int ind  = 0;

for(int j = 0;j<i;j++) ind = q[j]==i ? j : ind;

for(int j = 0;j<i;j++) b[(i+j-1-ind)%i] = q[j];

for(int j = 0;j<i;j++) q[j] = b[j];

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

}

for(int i = 0;i<n;i++) cout << ans[i] << " ";

cout << '\n';

}

return 0;

 

}