楼兰图腾 题解

题解

题目链接

 

题目中的第一个问题让我们求一个三元组( i , j , k)满足i  < j < k 并且 f( j )  <  f ( i ) 并且 f( j )< f ( k );

也就是让我们求逆序对。

我们不妨枚举中间的数j 先计算出j左边比f (j)大的数(j的逆序对)

再从后往前枚举 计算j右边比f(j)大的数

我们可以用树状数组记录每个数出现了多少次,每次枚举结束时把当前点加入到我们的树状数组里

 

最后根据乘法原理 把左边比当前数大的数的数量乘上右边大的数的数量即可

第二个问题同理

 

所以这道题实际考察的是树状数组求逆序对。

我们发现这道题的值域非常小是2e5,所以不需要离散化。

不然的话还得离线离散化,排序去重二分,啊这还得排序。

那不是直接归并排序来的更快点嘛。。。

 

代码如下:

#include<bits/stdc++.h>

using namespace std;

const int N = 200010;

int n;

typedef long long LL;
int a[N];


int lower[N],Greater[N];

int tr[N];


int lowbit(int x)
{
    return x & -x;
}

int sum(int x)
{
    int res = 0;
    for(int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
    
}

void add(int x,int c)
{
    for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}


int main()
{
    cin >> n;
    for(int i = 1; i <= n; ++ i) scanf("%d",&a[i]);
    for(int i = 1; i <= n; ++ i)
    {
        int y = a[i];
        lower[i] = sum(y - 1); //在i之前比ai小的数;
        Greater[i] = sum(n) - sum(y); //在i之前比ai大的数;
        add(y,1);
    }
    LL res1 = 0,res2 = 0;
    memset(tr,0,sizeof tr);
    for (int i = n; i >= 1; -- i)
    {
        int y = a[i];
        res1 += Greater[i] * (LL)(sum(n) - sum(y));
        res2 += lower[i] * (LL)(sum(y - 1));
        add(y, 1);
    }
     printf("%lld %lld\n", res1, res2);

    return 0;
    
}

 

posted @ 2021-08-02 14:56  Linyk  阅读(46)  评论(0编辑  收藏  举报