BNU 25586 Mega Inversions【樹狀數組求逆序數對和正序數對】

鏈接:




B. Mega Inversions

12000ms
3000ms
655360KB
64-bit integer IO format: %lld      Java class name: Main
Font Size:  

The n2 upper bound for any sorting algorithm is easy to obtain: just take two elements that are misplaced with respect to each other and swap them. Conrad conceived an algorithm that proceeds by taking not two, but three misplaced elements. That is, take three elements ai > aj > ak with i < j < k and place them in order ak, aj , ai. Now if for the original algorithm the steps are bounded by the maximum number of inversions n(n-1)/2 , Conrad is at his wits' end as to the upper bound for such triples in a given sequence. He asks you to write a program that counts the number of such triples.

Input

 

The first line of the input is the length of the sequence, 1 <= n <= 105.
The next line contains the integer sequence a1, a2, ... , an.
You can assume that all ai are in [1, n].

Output

Output the number of inverted triples.

Sample Input

Sample Input 1
3
1 2 3

Sample Input 2
4
3 3 2 1

Sample Output

Sample Output 1
0

Sample Output 2
2




算法:樹狀數組



題意:


第一行 N 代表總共有 N 個數
第二行行依次給你 N 個數據

如果有這樣三個數 ai > aj > ak 而且 i < j < k. 那麼就算是一個inverted triples
讓你求這個數組中有多少個這樣的inverted triples


思路:


以每一個數爲中間的數,在它前面找一個比它大的數,在它後面找一個比它小的數就形成了一個inverted triples
那麼題目就轉化成了,求出每一個數前面有多少個數比它小,記爲 ans1, 後面有多少個數比它大,記爲 ans2。
然後 ans1*ans2 就是以這個數爲中間的數的對應的 inverted triples的數目。
那麼只要求出每一個數前面有多少數比它大,後面有多少個數比它小
依次記錄後遍歷相乘的結果即爲所求。



注意:數據比較小,You can assume that all ai are in [1, n].

      所以不用離散化。。。。比賽的時候求正序數對的時候各種離散化各種錯哭思路一下就明確了,代碼敲了一個小時還是各種錯。

      如此弱菜我還能說什麼呢。 


code:

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

const int maxn = 1e5+10;
int n;

int a[maxn]; //記錄每一個數 
int c[maxn];

long long ans1[maxn];
long long ans2[maxn];

int lowbit(int x)
{
	return x&(-x);
}

void add(int i)
{
	while(i <= n)
	{
		c[i]++;
		i += lowbit(i); 
	}
}

long long sum(int i)
{
	long long ret = 0;
	while(i > 0)
	{
		ret += c[i];
		i -= lowbit(i);
	}
	return ret;
}

int main()
{
	while(scanf("%d", &n) != EOF)
	{
		memset(a, 0, sizeof(a)); //清空 
		memset(c, 0, sizeof(c));
		
		memset(ans1, 0, sizeof(ans1));
		memset(ans2, 0, sizeof(ans2));
		
		for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
		
		for(int i = 1; i <= n; i++)
		{
			ans1[i] = sum(n) - sum(a[i]); //計算出現在 a[i] 前面比 a[i] 大的數的個數:總數- <=a[i] 的數 
			add(a[i]); //插入當前數據 
		}
		memset(c, 0, sizeof(c)); //重新清零 
		for(int i = n; i >= 1; i--) //逆序插入 
		{
			ans2[i] = sum(a[i]-1); //計算出現在 a[i] 後面但是比 a[i] 小的數的個數 
			add(a[i]); //插入當前數據 
		}
		
		long long ans = 0;
		for(int i = 1; i <= n; i++)
			ans += ans1[i]*ans2[i];  //前面比它大*後面比它小 
		printf("%lld\n", ans);
	}
	return 0;
}

 





總結:

        2013年暑假第四次組隊賽了,比完了明天的,我就可以回家了開始暑假了。
      作爲一支老生隊伍,這幾次的成績實在是弱爆了。
      比賽開始,一如既往的由 Orc 童鞋 AC 那道簽到題,然後他看錯了題目 WA了一次,很快改對了,然後這時過了半個小時吧。排第五。一如既往的被所有的老生隊伍踩,外加兩支新生隊伍踩。。。這個時候我在看第一題的搜索。感覺 DFS 還是很有問題,題目稍微編變換,數據大一點我就無法解決,我們隊的搜索又都很弱。然後糾結了下,做不出,沒有搞了。然後我發現很多人過了的 D 電梯那題是個 DP 但是 DP弱菜們遞推不出公式,然後我們兩個就是各種看題,各種悲催,很快所有的隊伍都做完了簽到題目,由於我們隊 WA 了一次,然後就慘淡的墊底了。
       然後就是三個小時沒有提交。。。。三個小時後期 Orc 用 BFS 寫那個 DP 的題目,我開始糾結 E 字符串的那題,見到過很多次,但是以前都覺得自己做不出,沒有仔細想過,寫的時候字符串的分離也出了些問題,後來和 Orc 討論了些細節問題,自己慢慢敲,感覺過不了,但是此時已經三點半了我們才一題墊底,這個時候Orc 的 BFS 寫電梯的題目也敲完了,然後隨便測試了下我的,我說不管了,交吧。反正情況不會比這個更慘,然後 1A 。然後 Orc 也交了 1 A
然後就這樣半秒鐘 1 A 了兩題,三點半的時候形式迅速逆轉,墊底的第七排到了第四。太屌絲逆襲了,不過總算是鬆了一口氣,心裏有底了。然後就剩下各種亂看題目,各種沒有思路。
        然後我仔細看了下了這個樹狀數組的題, 很快得出了思路。。。還剩不到一個小時,但是這個思路不是像上面說的那樣得到的這麼直接,然後又給 Orc 講了下,說服他相信我的思路,幫我解決細節問題,然後開始敲的時候已經只有半個小時了,然後沒有考慮到數據大小,受到以前的題目的慣性思維認爲數據很大,各種離散化,各種測試+各種錯。最後一分鐘用 __int64提交了,但是這個 OJ 要用 long long 果斷編譯錯誤,賽後各種改,還是錯了。
       

開始的時候能夠一下 AC 兩題應該是處於灰心的狀態,反正不會比這個更慘了,慢慢折騰吧。然後心態比較平和就 1A 了
一下過了兩題能不興奮嗎,特別是我等弱菜,然後情緒迅速高漲,然後就是慘淡的錯。。。。。。即便是思路明確了。
所以比賽的時候能力已經定了,心態纔是扭轉局面的關鍵。

       然後就是一如既往的被兩支老生隊伍踩,被兩支新生隊伍踩。。。。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章