您的位置:首页 > 其它

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

2017-07-26 18:36 411 查看

问题 G: Balanced Photo

时间限制: 1 Sec  内存限制: 128 MB
提交: 67  解决: 17

[提交][状态][讨论版]

题目描述

Farmer John is arranging his N cows
in a line to take a photo (1≤N≤100,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
eef2
compute the total number of unbalanced cows.

输入

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

输出

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

样例输入

7
34
6
23
0
5
99
2

样例输出

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: