cursor: url(https://files-cdn.cnblogs.com/files/zouwangblog/cursor.ico),auto;

2018-正睿 2018 提高组十连测 Day6T1-Tiny Counting

题目描述

这里你需要解决一道微型计数题——关于人畜无害的四元组。

给定长度为 n 的数组 S,下标为 1∼n,你需要统计有多少个四元组 (a,b,c,d)(a,b,c,d) 满足:1≤a<b≤n;1≤c<d≤n;Sa<Sb;Sc>Sd,且 a,b,c,d互不相等。

输入格式

第一行一个正整数 n 表示 S 数组的长度。

第二行 n 个正整数,表示 S 数组的值。

输出格式

一行一个正整数表示四元组的数目。

样例一

input

4
1 4 3 2

output

3

explanation

(a,b,c,d)∈{(1,2,3,4),(1,3,2,4),(1,4,2,3)}.

样例二

input

5
9 1 0 0 5

output

8

限制与约定

对于20%的数据,n≤100;
对于50%的数据,n≤1000;
另外20%的数据,0≤Si≤1;
对于100%的数据,n≤10^5;0≤Si≤10^9.

时间限制:2s
空间限制:512MB

 



题解:
第一道就是毒瘤的说,当然还好。
题目中描述(a,b),(c,d)两种二元组的个数很容易用树状数组求出(先离散一下)。

用t1代表(a,b)的个数,t2代表(c,d)的个数,那么t1*t2就是(a,b,c,d)的个数,但有点差别,这里的(a,b,c,d)可能会有位置相同的情况。
所以t1*t2还要减去一些重复的情况。
有哪些重复情况呢:
很简单:a=c,a=d,b=c,b=d。
分别用树状数组求出四种情况的方案数,从答案中减去就行了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=1e5+5;
ll n,s[N],c[N],ans,c1[N],c2[N];
struct node{ll x,id;}p[N];
bool cmp(node a,node b){return a.x<b.x;}
void add(ll x,ll c[]){while(x<=n)c[x]++,x+=x&-x;}
void del(ll x,ll c[]){while(x<=n)c[x]--,x+=x&-x;}
ll ask(ll x,ll c[]){
    ll ret=0;
    while(x>0)ret+=c[x],x-=x&-x;
    return ret;
}
int main()
{
    ll i,t1=0,t2=0,tot=0;
    scanf("%lld",&n);
    for(i=1;i<=n;i++)scanf("%lld",&p[i].x),p[i].id=i;
    p[0].x=-1e8;
    sort(p+1,p+1+n,cmp);
    for(i=1;i<=n;i++){
        if(p[i].x!=p[i-1].x)tot++;
        s[p[i].id]=tot;
    }
    for(i=1;i<=n;i++)t1+=ask(s[i]-1,c),add(s[i],c);
    memset(c,0,sizeof(c));
    for(i=n;i>=1;i--)t2+=ask(s[i]-1,c),add(s[i],c);
    ans=t1*t2;
    for(i=1;i<=n;i++){
        t1=ask(s[i]-1,c1),t2=ask(tot-s[i],c2);
        add(s[i],c1),add(tot-s[i]+1,c2);
        ans-=t1*t2;
    }
    memset(c1,0,sizeof(c1)),memset(c2,0,sizeof(c2));
    for(i=1;i<=n;i++)add(s[i],c2);
    for(i=1;i<=n;i++){
        t1=ask(s[i]-1,c1),t2=ask(s[i]-1,c2);
        add(s[i],c1),del(s[i],c2);
        ans-=t1*t2;
    }
    memset(c1,0,sizeof(c1));
    for(i=1;i<=n;i++)add(tot-s[i]+1,c1),add(s[i],c2);
    for(i=1;i<=n;i++){
        t1=ask(tot-s[i],c1),t2=ask(s[i]-1,c2);
        del(tot-s[i]+1,c1),del(s[i],c2);
        ans-=t1*t2;
    }
    for(i=1;i<=n;i++)add(tot-s[i]+1,c1);
    for(i=1;i<=n;i++){
        t1=ask(tot-s[i],c1),t2=ask(tot-s[i],c2);
        del(tot-s[i]+1,c1),add(tot-s[i]+1,c2);
        ans-=t1*t2;
    }
    cout<<ans;
}
View Code

 

posted @ 2018-09-30 16:43  Art-Yrr  阅读(485)  评论(0)    收藏  举报