题解 P3608 【[USACO17JAN]Balanced Photo平衡的照片】

题目

一道树状数组的裸题。

值得一提的是题目的翻译貌似有点问题。

如果L[i]和R[i]的数目相差2倍以上的话,第i头奶牛就是不平衡的。(L[i]和R[i]分别代表第i头奶牛左右两边比她高的数量)。如果L[i]和R[i]中较大者比较小者的数量严格多两倍的话,这头奶牛也是不平衡的

题目中这段话的意思其实是\(max(l[i], r[i]) > 2 * min(l[i], r[i])\),不要被误导了。

接下来是正题。

首先看到这道题,不难想到\(O(n^2)\)的暴力做法,即枚举,但是这样显然会超时,需要优化。

我们发现,题目中要求的东西其实就是一个点左边和右边比他大的点的数量,所以我们枚举的时候其实是浪费了很多时间的,因为一个点的信息并非和其他点没有关联,我们想想怎么能够利用这些信息。

对于一个序列中的某个数,只有比他大的数才会产生影响,所以一个很显然的想法是先从大到小排序。

考虑排序以后,当你操作到\(a[i]\)这个数时,比他大的数一共有\(n-i\)个,也就是说只要你求出这个点左边比他大的数的数量,就可以求出右边的数量。那么你在插入这个数时产生的贡献就是把这个数后面的比他小的数的答案+1。

举个例子,现在有序列3 2 5 1

当你插入3时,2和1的答案都会+1

那么其实就是求一个单点修改的前缀和,每次插入一个数就把这个位置的值从0变成1,然后对于某一个位置\(i\),左边比他大的数就只需要查询一个前缀和就行了。

用树状数组维护,代码也很简洁。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000005;
struct sCow
{
    int iH, iBh;
}Cow[N];
bool cmp(sCow x, sCow y){return x.iH > y.iH;}
int iSum[N], n;
int lowbit(int x) {return x & -x;}
void Add(int x, int k){for(; x <= n; x += lowbit(x)) iSum[x] += k;}
int Query(int x){int ans = 0;for(; x; x -= lowbit(x)) ans += iSum[x];return ans;}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &Cow[i].iH), Cow[i].iBh = i;
    sort(Cow + 1, Cow + 1 + n, cmp);
    int iAns = 0;
    for(int i = 1; i <= n; i++)
    {
        Add(Cow[i].iBh, 1);
        int l = Query(Cow[i].iBh - 1);
        int r = i - l - 1;
        if(max(l, r) > 2 * min(l, r)) iAns++;
    }
    cout<<iAns;
}

猜你喜欢

转载自www.cnblogs.com/lcezych/p/12114133.html