題意:1~n的數按順序間隔排列,(1 2 3 4 ... n) 中間的空格也要佔一位,現在有一種操作,每次把序列最後面那個數移到離它最近的空格里面,直到前n個位置都被填滿,沒有空格了。給出q次查詢,每次輸入一個數 Xi,要求輸出按照所給操作完成後的Xi位置上的數是多少。
題解:題目上給的數據範圍超級大(1e18),所以肯定是不能模擬的,一定有什麼規律在裏面。首先很容易發現,不是根本不用發現,我們就知道一開始所有的數字使在奇數下標的位置上,每次我們移動一個數都是移動到一個偶數位置上,同時前n個數中,奇數位置上的數是不會動的,因爲後面的數填空都是填到偶數下標位置上,而填到第n個數的時候前面的空位科寧已經被填滿了,他們會一直保持在奇數位置上,所以當查詢的位置是奇數時,我們可以直接輸出原位置上的數,而這個數是非常好得到的(原來每個數是空一個放一個,那數x的下標就是(2x-1),所以知道下標Xi,求位置上的數就是(Xi+1)/2)。而當查詢的是偶數位置上的數時,我們假設當前這個偶數位置是p,那麼這個位置前面一定有p/2個數,它後面就有(n-p/2),包括當前位置上的數,所以這個數是從p+n-p/2的位置跳到當前這個位置上的(體會一下,既然能跳到這個位置上,那一定是後面每空格了全是數,所以纔會跳到這裏),那我們只用一直向後推,推到什麼時候才能得到它最初的位置呢?答案就是當到了一個奇數位置的時候,因爲我們已經講過所有的數一開始就是在奇數位置上,而他們每次跳都會跳到偶數位置上。得到了最初位置就可以用剛剛我們推出來的用位置下標算數的大小的式子計算了。
附上代碼(非常簡短易懂 ):
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { ll n,x; int q; scanf("%I64d%d",&n,&q); for(int i=1;i<=q;i++) { scanf("%I64d",&x); long long num; if(x&1)//奇數位置直接算 num=(x+1)/2; else { while(x%2==0)//向後推這個位置上的數的最初位置 x+=(n-x/2); num=(x+1)/2; } printf("%I64d\n",num); } return 0; }