【CUGBACM15级BC第23场 B】hdu 5147 Sequence II

70 篇文章 0 订阅
9 篇文章 0 订阅

Sequence II

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1281    Accepted Submission(s): 523


Problem Description
Long long ago, there is a sequence A with length n. All numbers in this sequence is no smaller than 1 and no bigger than n, and all numbers are different in this sequence.
Please calculate how many quad (a,b,c,d) satisfy:
1. 1a<b<c<dn
2. Aa<Ab
3. Ac<Ad
 

Input
The first line contains a single integer T, indicating the number of test cases.
Each test case begins with a line contains an integer n.
The next line follows n integers A1,A2,,An .

[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= Ai <= n
 

Output
For each case output one line contains a integer,the number of quad.
 

Sample Input
  
  
1 5 1 3 2 4 5
 

Sample Output
  
  
4
 

首先分析题干:这里的四元组除了位子有相关的大小限制条件之外呢,我们是没有任何相关的关系的,所以我们这里拆分成两个二元组来做。例如样例:

从3开始,13能够组成一组二元组,3之后能够形成3组二元组。

然后是2,1 2能够组成一组二元组,2之后能够形成1组二元组。

然后相乘并且相加1*3+1*1得到结果4.所以呢,我们这里的思维就很好形成了。找到当前数字之前的数字里边比他小的数字和,就是他之前和他能够组成的二元组的组数。

然后再找到这个数之后能够形成的组数。然后相乘就能得到结果。

但是这里,当前数字之后的组数是如何计算的呢?我们这里拿样例来说明。从后向前计算:

5 之后没有数据,能够形成0组二元组。

4之后5比他大,能够形成1组二元组。这里表示数字2之后能够形成1组二元组。

2之后4 5比他大,2 4 2 5能够形成两组二元组 ,加上 4 5的二元组,这里表示数字3之后能够形成3组二元组。

3之后 4 5比他大 3 4 3 5能够形成两组二元组 ,加上 2 4 2 5 4 5三组,这里表示数字1之后能够形成5组二元组。依次类推即可

解题思路:
要统计四元组的数量我们可以通过枚举c,然后统计区间[1,c-1]有多少二元组(a,b)满足a<b且Aa<Ab,以及统计出区间[c+1,n]有多少d满足Ac<Ad,
根据乘法原理,把这两项乘起来就可以统计到答案里了.然后我们来处理子问题:区间[1,c-1]内有多少二元组(a,b).那么我们可以枚举b,然后统计
区间[1,b-1]内有多少a满足Aa<Ab,那么这个可以通过用树状数组询问前缀和来实现.

具体实现:b[i]和c[i]中存储的分别为以i结尾的Ax<Ay的对数和从i+1到n中Ax<Ay的对数,二者相乘即为答案。
时间复杂度是O(nlogn).
#include<bits/stdc++.h>
#include <ctime>
using namespace std;
typedef long long ll;

int n;
int tree[55000];
int b[55000], c[55000], a[55000];
int lowbit(int x)
{
    return x & (-x);
}
int sum(int x)
{
    int sum = 0;
    while (x > 0)
    {
        sum += tree[x];
        x -= lowbit(x);
    }
    return sum;
}
void add(int x, int c)
{
    while (x <= n)
    {
        tree[x] += c;
        x += lowbit(x);
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t--)
    {
        memset(b, 0, sizeof(b));
        memset(c, 0, sizeof(c));
        memset(a, 0, sizeof(a));
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
        }

        memset(tree, 0, sizeof(tree));
        for (int i = 1; i <= n; i++)
        {
            b[i] = sum(a[i]);
            add(a[i], 1);
        }

        memset(tree, 0, sizeof(tree));
        for (int i = n; i >= 1; i--)
        {
            c[i] = sum(n) - sum(a[i]) + c[i + 1];
            add(a[i], 1);
        }

        ll ans = 0;
        for (int i = 2; i <= n - 2; i++)
        {
            ll x = b[i];
            ll y = c[i + 1];
            ans += x * y;
        }
        cout << ans << endl;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值