BNU 25586 Mega Inversions【树状数组求逆序数对和正序数对】

链接:

http://www.bnuoj.com/bnuoj/problem_show.php?pid=25586

http://www.bnuoj.com/bnuoj/contest_show.php?cid=2321#problem/25863


B. Mega Inversions

Time Limit: 12000ms
Case Time Limit: 3000ms
Memory Limit: 655360KB
64-bit integer IO format:  %lld      Java class name:  Main
Submit  Status  PID: 25586
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 <= 10 5.
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
Submit  Status  PID: 25586




算法:树状数组



题意:


第一行 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 了
一下过了两题能不兴奋吗,特别是我等弱菜,然后情绪迅速高涨,然后就是惨淡的错。。。。。。即便是思路明确了。
所以比赛的时候能力已经定了,心态才是扭转局面的关键。

       然后就是一如既往的被两支老生队伍踩,被两支新生队伍踩。。。。

你可能感兴趣的:(树状数组)