zoukankan      html  css  js  c++  java
  • hdu5792 World is Exploding(多校第五场)树状数组求逆序对 离散化

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5792

    题目描述:给你n个值,每个值用A[i]表示,然后问你能否找到多少组(a,b,c,d)四个编号,四个编号互不相同,然后a < b, c < d,a代表的值小于b代表的值,c代表的值大于d代表的值。

    解题思路:先考虑a和b这两个编号,遍历每一个编号作为b,然后找到b前面有多少个小于b的值,就是对于这一个编号b合理的编号a,对于每一组a和b,就可以考虑c和d,能够满足条件c和d的很显然就是除去a和b整个序列有多少个逆序对,对吧。然后对于每一个b有x个a满足条件,所以对于当前b,能够满足条件的就是(x*所有的逆序对的个数 - 逆序对中包涵a和b的个数)。所有逆序对很容易就可以用树状数组求出来,x也就是b前面有多少个小于编号b代表的值得个数,也很容易求出来,然后包涵a和b个数的逆序对呢,a前面大于A[a]的个数和a后面小于A[a]的个数,b也是一样的。

    设x为对于每个b满足条件的a的个数,na代表和a有关系的逆序对,nb代表和b有关系的逆序对,tot代表所有的逆序对个数,然后对于每一个b就有 tot*x - nb*x - (所有na的值)。

    代码:

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<cstring>
    #include<queue>
    #include<set>
    #include<string>
    #include<map>
    #define inf 9223372036854775807
    #define INF 9e7+5
    #define PI acos(-1)
    using namespace std;
    typedef long long ll;
    typedef double db;
    const int maxn = 5e4 + 5;
    const int mod = 1e9 + 7;
    const db eps = 1e-9;
    ll n, c[maxn], a[maxn], num[maxn], tot, cc[maxn], lar[maxn], b[maxn];
    
    struct pos {
        ll a, ord, la;
    } q[maxn];
    
    void init() {
        tot = 0;
        memset(c, 0, sizeof(c));
        memset(cc, 0, sizeof(cc));
        memset(lar, 0, sizeof(lar)); //这个数组好像不用初始化
    }
    
    ll lowbit(ll x) {
        return x & (-x); //求最低位
    }
    
    void updata(ll x, ll p, ll u[]) { //更新
        while (x <= maxn) {
            u[x] += p;
            x += lowbit(x);
        }
    }
    
    ll getsum(ll x, ll u[]) {
        ll ans = 0;
        while (x > 0) {
            ans += u[x];
            x -= lowbit(x);
        }
        return ans;
    }
    bool cmp1(const pos&a, const pos&b)
    {
        return a.a<b.a;
    }
    bool cmp2(const pos&a, const pos&b){
        return a.ord<b.ord;
    }
    
    void solve() {
        while (cin >> n) {
            init();
            for (int i = 1; i <= n; i++) {
                scanf("%I64d", &q[i].a);
                q[i].ord = i;
            }
            int pp = 0; sort(q+1, q+1+n, cmp1);
            q[0].a = -1;
            for (int i = 1; i <= n; i++) { //离散化
                if (q[i].a != q[i-1].a) q[i].la = ++pp;
                else {
                    q[i].la = pp;
                }
            }
            sort(q+1, q+1+n, cmp2);
            for (int i = 1; i <= n; i++) {
                lar[i] = i - getsum(q[i].la, c) - 1; //求出每个数前面
                updata(q[i].la, 1, c);              //有多少比他大的数
            }
            memset(c, 0, sizeof(c));
            for (int i = n; i >= 1; i--) {
                num[i] = getsum(q[i].la-1, c);          //求出每个数的
                updata(q[i].la, 1, c); tot += num[i]; //后面比他小的个数
            }
            ll ans = 0; memset(c, 0, sizeof(c));
            for (int i = 1; i <= n; i++) {
                ll tmp = getsum(q[i].la-1, c);   //对当前b满足条件的a的个数
                updata(q[i].la, 1, c);  
                ll tt = getsum(q[i].la-1, cc);  //求出和a有关系的逆序对
                updata(q[i].la, num[i] + lar[i], cc);//num[i]+lar[i]就是和a有关系的逆序对
                ans += tmp * tot - tt - (num[i]+lar[i])*tmp;//这里的num[i]+lar[i]是和b有关系的逆序对
            }
            cout << ans << endl;
        }
    }
    
    int main(){
        //cin.sync_with_stdio(false);
        //freopen("tt.txt", "r", stdin);
        //freopen("isharp.out", "w", stdout);
        solve();
    
        return 0;
    }
    

      

  • 相关阅读:
    LeetCode(81): 搜索旋转排序数组 II
    2018年6月8日论文阅读
    LeetCode(80):删除排序数组中的重复项 II
    LeetCode(79): 单词搜索
    LeetCode(78):子集
    LeetCode(77):组合
    LeetCode(76): 最小覆盖子串
    LeetCode(75):分类颜色
    LeetCode(74):搜索二维矩阵
    linux 两个查找工具 locate,find
  • 原文地址:https://www.cnblogs.com/ost-xg/p/5730590.html
Copyright © 2011-2022 走看看