zoukankan      html  css  js  c++  java
  • 楼兰图腾 题解

    题解

    题目链接

    题目中的第一个问题让我们求一个三元组( 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
    ", res1, res2);
    
        return 0;
        
    }
  • 相关阅读:
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
  • 原文地址:https://www.cnblogs.com/yjyl0098/p/15089907.html
Copyright © 2011-2022 走看看