hdu5792--World is Exploding

题意:给一个数列,求四个各不相同的数,一个逆序对,一个正序对,求多少组这样的四个数。

题解:辣鸡如我,还是上官方题解了。

rg(i)就是i右边比i大的数的个数,rs(i)就是i右边比i小的数的个数。

lg(i)就是i左边比i大的数的个数,ls(i)就是i左边比i小的数的个数。

allg就是所有逆序对的个数,∑rs(i)或者∑lg(i)都可以。

然后答案就是对于每一个数,当它为正序对中较小的那个数时的答案相加。

这样算会有重复,就是那个正序对中较大的数也被算入了逆序对中,所以再减去每个数字作为正序对较大的数时的它所可能的逆序对数量。

注意用会超int 用long long

// 2016多校5-1012/hdu5792
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define PF(x) cout << "debug:" << x << " ";

const int N = 50005;
typedef long long ll;
int a[N], b[N];
int lg[N], ls[N], rg[N], rs[N];

int bit[N];

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

void add(int p, int v, int n)
{
    while (p <= n) {
        bit[p] += v;
        p += lowbit(p);
    }
}

ll sum(int p)
{
    ll ans = 0;
    while (p > 0) {
        ans += bit[p];
        p -= lowbit(p);
    }
    return ans;
}

int main(int argc, char const *argv[])
{
    freopen("in", "r", stdin);
    int n;
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) {
            scanf("%d", a+i);
            b[i] = a[i];
        }
        //离散话
        sort(a+1, a+n+1);
        int tot = unique(a+1, a+n+1) - a;
        for (int i = 1; i <= n; ++i) {
            b[i] = lower_bound(a, a+tot, b[i]) - a;
        }
        //for (int i = 1; i <= n; ++i) printf("%d\n", b[i]);
        //求lg ls
        memset(bit, 0, sizeof bit);
        for (int i = 1; i <= n; ++i) {
            ls[i] = sum(b[i]-1);
            lg[i] = i - 1 - sum(b[i]);
            add(b[i], 1, n);
        }
        //求rg rs
        memset(bit, 0, sizeof bit);
        for (int i = n; i > 0; --i) {
            rs[i] = sum(b[i]-1);
            rg[i] = n - i - sum(b[i]);
            add(b[i], 1, n);
        }
        // cout << "ls "; for (int i = 1; i <= n; ++i) printf("%d ", ls[i]); printf("\n");
        // cout << "lg "; for (int i = 1; i <= n; ++i) printf("%d ", lg[i]); printf("\n");
        // cout << "rs "; for (int i = 1; i <= n; ++i) printf("%d ", rs[i]); printf("\n");
        // cout << "rg "; for (int i = 1; i <= n; ++i) printf("%d ", rg[i]); printf("\n");
        //求allg
        ll allg = 0;
        for (int i = 1; i <= n; ++i) allg += lg[i];
        //PF(allg);
        ll ans = 0;
        for (int i = 1; i <= n; ++i) {
            ans += (ll)rg[i] * (allg - lg[i] - rs[i]);
        }
        for (int i = 1; i <= n; ++i) {
            ans -= (ll)ls[i] * (lg[i] + rs[i]);
        }
        cout << ans << endl;
    }
    return 0;
}
时间: 2024-10-18 05:04:14

hdu5792--World is Exploding的相关文章

hdu-5792 World is Exploding(容斥+树状数组)

题目链接: World is Exploding Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>A

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和

HDU5792 World is Exploding(树状数组)

一共6种情况,a < b且Aa < Ab, c < d 且Ac > Ad,这两种情况数量相乘,再减去a = c, a = d, b = c, b = d这四种情况,使用树状数组维护,le[i]表示i左边比他小的数数量,le1[i]表示i左边比他大的数数量,ri[i]表示i右边比他小的数数量,ri1[i]表示i右边比他大的数数量. 跑两次树状数组,求出这四个数组值. 注意处理数值相等的情况. #include<cstdio> #include<iostream>

hdu 5792 World is Exploding(2016 Multi-University Training Contest 5——树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5792 World is Exploding Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 643    Accepted Submission(s): 306 Problem Description Given a sequence A

2016 Multi-University Training Contest 5 1012 World is Exploding 树状数组+离线化

1012 World is Exploding 题意:选四个数,满足a<b and A[a]<A[b]   c<d and A[c]>A[d] 问有几个这样的集合 思路: 树状数组+离线化 先处理出每个数左边比它小 大,右边比它大 小的数目,用cnt[][i]表示.最后统计一下减去重复的就可以 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <

HDU 5792:World is Exploding(树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=5792 World is Exploding Problem Description Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad. Input The input consists of multiple test

World is Exploding 树状数组+离散化

Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ada≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad. InputThe input consists of multiple test cases. Each test case begin with an int

HDU 5792 L - World is Exploding

题目,要求找出有多少对这样的东西,四个数,并且满足num[a]<num[b] &&num[c]>num[d] 要做这题,首先要懂得用树状数组,我设,下面的小于和大于都是严格的小于和大于 dpL_min[i]:表示在第i个数往左,(不包括第i个),有多少个数是少于num[i]的 dpL_max[i]:表示在第i个数往左,(不包括第i个),有多少个数是大于num[i]的 dpR_min[i]:表示在第i个数往右,(不包括第i个),有多少个数是小于num[i]的 dpR_max[i]

HDU 5792 World is Exploding

预处理出每个数字前面比它小的有几个,比他大的有几个,后面比他小的有几个,比他大的有几个. 先算出最多可能产生多少对,然后减去多加的就是答案. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector>