ACM暑假训练 问题 G: Balanced Photo (树状数组优化)

来源:互联网 发布:淘宝店铺装修模板复制 编辑:程序博客网 时间:2024/06/06 02:04

问题 G: Balanced Photo

时间限制: 1 Sec  内存限制: 128 MB
提交: 67  解决: 17
[提交][状态][讨论版]

题目描述

Farmer John is arranging his N cows in a line to take a photo (1N100,000). The height of the ith cow in sequence ishi, and the heights of all cows are distinct. 
As with all photographs of his cows, FJ wants this one to come out looking as nice as possible. He decides that cow i looks "unbalanced" if Li and Ri differ by more than factor of 2, where Li and Ri are the number of cows taller than i on her left and right, respectively. That is, i is unbalanced if the larger of Li and Ri is strictly more than twice the smaller of these two numbers. FJ is hoping that not too many of his cows are unbalanced.

Please help FJ compute the total number of unbalanced cows.

输入

The first line of input contains N. The next N lines contain h1hN, each a nonnegative integer at most 1,000,000,000.

输出

Please output a count of the number of cows that are unbalanced.

样例输入

73462305992

样例输出

3

提示

In this example, the cows of heights 34, 5, and 2 are unbalanced.


【解析】:

十万的数据量,两层循环必定超时。


先给这个数列排排名次,不妨让最小的当第一名,最高的当最后一名,

这样得到一个排名的数列,而且不会改变原数列的前后之间的大小关系。不妨令此数列为数组d


有了数列 d,我们从左往右扫一遍数列 d。另外申请一个数组 c 做辅助。


c[ i ] 表示i左边比 d[ i ] 小的数目。


扫到d[ i ] 的时候用temp=c[ i ] 得到当前i的前面有多少个比d[ i ] 小的数。再用i-temp+1即得到了左边的大数的数目。

然后让所有的小于d[i]的 j ,使得c[ j ]加1。表示比d[i]小的数目全都加1

与此同时,记录下i左边的大的数,存入L[ i ];


代码说一下就是:

for(int i=1;i<=n;i++){int temp=c[i];//i左边的矮牛数L[i]=i-temp-1;//i左边的高牛数for(int j=1;j<=d[i];j++)c[j]++;}

但是这样必定超时,所以数组c用树状数组来维护,就可以避免内层for循环。复杂度从O(n^2)降到O(n*log(n));


如上,左边的高牛数完了,把数列倒过来再数一遍得到R[ i ]。


【代码】:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int n,c[520000],a[520000];int t[520000],d[520000];int L[520000],R[520000];bool cmp(int x,int y){return a[x]<a[y];}void add(int k,int num){while(k<=n){c[k]+=num;k+=k&-k;}}int find(int k){int sum=0;while(k){sum+=c[k];k-=k&-k;}return sum;}int main(){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];t[i]=i;}sort(t+1,t+1+n,cmp);for(int i=1;i<=n;i++){d[t[i]]=i;//身高序号}//数组d把原序列按大小分配序号,但原序列不变 for(int i=1;i<=n;i++)//从左数牛 {int temp=find(d[i]);//i左边的矮牛数L[i]=i-temp-1;//i左边的高牛数add(d[i],1);}memset(c,0,sizeof(c));//树状数组清0 for(int i=n;i>=1;i--)//从右边数得到右边,原理同左 {int temp=find(d[i]);//i右边的矮数目 R[i]=n-i-temp;  //i右边的高牛数目 add(d[i],1);}int ans=0;for(int i=1;i<=n;i++){if(2*min(L[i],R[i])<max(L[i],R[i]))ans++;}cout<<ans<<endl;return 0;}