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

题目链接:https://www.luogu.org/problemnew/show/P3608

乍一看很容易想到O(N^2)的暴力。

对于每个H[i]从i~i-1找L[i]再从i+1~n找R[i],然后比较。

60分(数据够水)

但是这个思路就是很直白的模拟,让人不容易想到如何去优化。

然后我们换一个也是差不多O(N^2)的思路:

我们设法把H[i]所对应的第k大的k求出来。

for example:

H 34 6 23 0 5 99 2
Kth 2 4 3 7 5 1 6

那么我们就能发现,对于第一个思路从i~i-1找一遍再从i+1~n找一遍这样两遍的遍历可以变成:

从1~i遍历,计数比当前Kth[i]小的作为L[i],那么R[i] = Kth[i] - L[i] - 1.

这个思路是有优化空间的。

到目前为止,我们需要的是快速的求出L[i]。

设想我们有一个初始全为0的长度为n的序列,从Kthx开始每次在这个序列的第Kth[x]的位置上加1,这样维护到当前第i个Kth时,前i-1Kth是维护过的,如果有比当前第Kth[i]小的就一定会提前处理过(在序列位置上加1)。

于是我们保证了答案的顺序不会出现问题。

就可以采用树状数组维护:

变成一个单点修改,查询0~i的和的问题。

code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
struct cow{
    int val, pos;
}a[maxn];
bool cmp(cow a, cow b)
{
    return a.val > b.val;
}
int n, answer, b[maxn];
class BIT{
    public:
        int tree[maxn<<2];
        void update(int pos, int val)
        {
            while(pos <= n)
            {
                tree[pos] += val;
                pos += lowbit(pos);
            }
        }
        int query(int pos)
        {
            int res = 0;
            while(pos)
            {
                res += tree[pos];
                pos -= lowbit(pos);
            }
            return res;
        }
    private:
        int lowbit(int x)
        {
            return x & -x;
        }
}T;
int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d",&a[i].val);
        a[i].pos = i;
    }
    sort(a + 1, a + 1 + n, cmp);
    for(int i = 1; i <= n; i++) b[a[i].pos] = i;
    for(int i = 1; i <= n; i++)
    {
        int L = T.query(b[i]);
        int R = b[i] - L - 1;
        if(L < R) swap(L, R);
        if(L > R + R) answer++;
        T.update(b[i], 1);
    }
    printf("%d",answer);
}

后记:

小trick:

求一个数列的Kth方法。

转载于:https://www.cnblogs.com/MisakaAzusa/p/11006300.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值