樹狀陣列 奇怪的報數遊戲

2021-08-20 02:56:45 字數 2014 閱讀 2591

大致思路

一看,序列,資料很大,暴力可能就是去遍歷,題中還有「前面有多少」的字眼,感覺就是用樹狀陣列做。

正向分析感覺有點困難,我們反向來想,如果是序列的最後乙個人,他前面有a人的編號比自己小,而他前面就是除他之外的所有人,所以他的編號應該就是a+1. 

那麼倒數第二個人呢?他前面的人是除他 而且除去最後乙個人之外的所有人,所以不僅考慮前面還要考慮後面!

我現在知道的資訊是:編號應該是所有比他編號小的人數+1,而所有比他編號小的人數=前面比他編號小的+後面比他編號小的。而前面比他編號小的就是a[i],而後面比他編號小的。。。。想到逆序對的思路了嗎。。。。。就是sum(i)!

因此,我不知道它會在哪,但是我知道它應該在哪——需要根據條件「m-1=a[i]+sum(i)」去尋找它的位置——》二分法!!!

當然,對於最後乙個人,顯然它的a[i]沒有意義,所以我就去看看最後哪個位子是空的,那麼它就應該在那兒。

但是對於二分法的細節問題又來了:只要滿足這個條件就行了?其實還必須要考慮「衝突機制」!!!!(這個真的是學到了)。你要去想有沒有可能位子上有衝突,思考的答案是有的——如果你二分法落到乙個已經有人坐的位子上,而碰巧,這個人的a[i]和你的a[i]相等,而同乙個位子上肯定sum(i)也相等,所以必然滿足條件m-1==sum(i)+a[i],那麼怎麼辦?他們的大小關係如何?有可能這兩個數(設為a,b,b是先坐上位子的那個人,也就是說b在原序列中是排在a後面的)相等 ; 有可能ab嗎?可能! 所以,我們應該把a往後移動,你會發現往後移的過程中 m也在+1,同時sum(m)也有可能在+1 ,也就一直滿足m-1==sum(i)+a[i](其中一直在衝突),直到不滿足的那一刻!你就應該退一步回去,那個位子肯定是空的,也是屬於你的。

ac**

#include#includeusing namespace std;

int c[500005];

long long sum(int i)

return res;

}int n;

void add(int i)

}int a[500005];

int ans[500005];

bool flag[500005];

int main()

add(a[n]+1); //最後乙個數的編號一定是比他編號小的數+1

ans[n]=a[n]+1;

flag[a[n]+1]=true;

//從後往前分析:已知前面比我小的,但是我的位置也該考慮後面比我小的。後面的已插入,用sum計算數量

//問題又來了:不知道該放在**!正確位置mid應滿足條件:mid-1==sum(mid-1)+a[i]

//二分法

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

add(mid);

ans[i]=mid;

flag[mid]=true;

} for(int mid=1;mid<=n;mid++) }

for(int i=1;i<=n;i++)

printf("%d\n",ans[i]);

return 0;

}

注意**中注釋了感嘆號的兩個地方,是二分法的注意事項。

我以前寫二分查詢,就是l=mid+1  r=mid-1,誰想今天覺得應該改改這個寫法了(因為我這樣寫在這道題通不過)。

首先,r的初值應該是乙個取不到的值(即能取到的最大值+1,如題中的n+1)。為什麼呢?因為mid=(l+r)/2 ,會發現由於除法結果會捨去小數部分的性質,你其實永遠都取不到r的值!!!!!第二點,你應該在mid值偏大即查詢的key值在左邊的時候使r=mid,此時如果r=mid-1那麼你有可能錯過mid-1這個可能解。而l仍然是mid+1,因為本來你l就取得到的,mid肯定不對。

學到就賺到,還要記到。

習題 奇怪的報數遊戲

思路 其中二分法就是用來判斷左右還剩幾個位置,是不是比每個人報的數大,大的話就填進去。像這個題目,可以先用暴力想一想該怎麼做,然後用區間資料結構來解決 比如這道題 include using namespace std const int max n 500050 int c max n 5 ran...

計蒜客 奇怪的報數遊戲

樹狀陣列 二分 這裡先給出乙個公式 第 i 個數的編號 i 之前比 i 小的總數量 i 之後比 i 小的總數量 1 例如 1 4 3 6 2 5 這個序列,我們可以用這個序列來驗證上述的公式,比如3 1 3前邊只有1比3小,所以只有1個 1 3後邊只有2比3小,所以只有1個 1,對吧。已經找出來的編...

約瑟夫環的實現《報數遊戲》

面試中經常會被問到報數遊戲。遂實現一下。問題描述 設有n個人圍坐一圈並按順時針方向從1到n編號,從第s個人開始進行1到m報數,報數到第m個人時,此人出圈,再從他的下乙個人重新開始1到m的報數,如此進行下去直到所有的人都出圈為止。現要列印出出圈次序。輸入 n 遊戲總人數 s 報數的起始編號 m 報數的...