[2010福建] 五元组问题 - 树状数组


题目描述

给定n个数字,组成数字串 A1, A2, …, An。
五元组{ i, j, k, s, t }满足以下两个条件:
  a) 1 ≤ i < j < k < s < t ≤ n
  b) Ai < Aj < Ak < As < At
例如,数字串{2, 1, 3, 4, 5, 7, 6}中,包含以下4个五元组{1, 3, 4, 5, 6}, {2, 3, 4, 5, 6}, {1, 3, 4, 5, 7} 和 {2, 3, 4, 5, 7}。
求给定数字串所包含的五元组的个数。


输入格式

第一行一个整数n(1≤n≤50,000),表示数字串包含n个数字。第二行包括n个数字A1, A2, …, An(1≤Ai≤1,000,000)。


输出格式

输出一行一个整数,表示五元组的个数。


样例数据

样例输入

【样例1】
5
1 2 3 4 5
【样例2】
7
2 1 3 4 5 7 6
【样例3】
7
1 2 3 4 5 6 7

样例输出

【样例1】
1
【样例2】
4
【样例3】
21


题目分析

欲做此题,先做此题
统计二元组是很简单的问题,用树状数组可以轻松搞定。
分析三元组:
i < j < k
Ai < Aj < Ak
因为二元组已经求出,故可以转化为
(i < j) < k
(Ai < Aj) < Ak
插入该三元组,清空原二元组数目,迭代统计比他小的刚刚统计完的二元组数目。
以此类推
一直推到五元组
不想写高精度了,打了biginteger


源代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline const int Get_Int() {
    int num=0,bj=1;
    char x=getchar();
    while(x<'0'||x>'9') {
        if(x=='-')bj=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9') {
        num=num*10+x-'0';
        x=getchar();
    }
    return num*bj;
}
struct BigInteger {
    static const int BASE=10000; //高进制
    static const int WIDTH=4; //高进制位数
    vector<int>s;
    BigInteger() { //构造函数:初始赋0
        *this=0;
    }
    BigInteger(long long num) { // 构造函数
        *this=num;
    }
    //赋值
    BigInteger operator = (long long num) {
        s.clear();
        do {
            s.push_back(num%BASE);
            num/=BASE;
        } while(num>0);
        return *this;
    }
    BigInteger operator = (const string& str) {
        s.clear();
        int x,len=(str.length()-1)/WIDTH+1;
        for(int i=0; iint end=str.length()-i*WIDTH;
            int start=max(0,end-WIDTH);
            sscanf(str.substr(start,end-start).c_str(),"%d",&x);
            s.push_back(x);
        }
        return *this;
    }
    //比较
    bool operator < (const BigInteger& b) {
        if(s.size()return true;
        if(s.size()>b.s.size())return false;
        for(int i=s.size()-1; i>=0; i--) {
            if(s[i]return true;
            if(s[i]>b.s[i])return false;
        }
        return false;
    }
    bool operator >= (const BigInteger& b) {
        return !(*thisbool operator <= (const BigInteger& b) {
        return !(*this>b);
    }
    bool operator == (const BigInteger& b) {
        if(s.size()!=b.s.size())return false;
        for(int i=0; iif(s[i]!=b.s[i])return false;
        return true;
    }
    bool operator != (const BigInteger& b) {
        return !(*this==b);
    }
    bool operator > (const BigInteger& b) {
        return ((*this>=b)&&(*this!=b));
    }
    //+
    BigInteger operator + (BigInteger& b) {
        BigInteger c;
        c.s.resize(max(s.size(),b.s.size())+1);
        for(int i=0; i1; i++) {
            int tmp1,tmp2;
            if(i>=s.size())tmp1=0;
            else tmp1=s[i];
            if(i>=b.s.size())tmp2=0;
            else tmp2=b.s[i];
            c.s[i]=tmp1+tmp2;
        }
        for(int i=0; i1; i++) {
            c.s[i+1]+=c.s[i]/BASE;
            c.s[i]%=BASE;
        }
        while(c.s.back()==0&&c.s.size()>1)c.s.pop_back();
        return c;
    }
    void operator += (BigInteger& b) {
        *this=*this+b;
    }
};
ostream& operator << (ostream& output,const BigInteger& x) {
    output<for(int i=x.s.size()-2; i>=0; i--) {
        char buf[20];
        sprintf(buf,"%04d",x.s[i]);
        for(int j=0; j<strlen(buf); j++)output<return output;
}
const int maxn=50005;
struct BIT { //树状数组(单点修改区间查询)
    int n;
    BigInteger c[maxn];
    inline int Lowbit(int x) { //低位操作 
        return x&(-x);
    }
    void init(int n) {
        for(int i=1; i<=n; i++)c[i]=0;
        this->n=n;
    }
    void add(int x,BigInteger v) { 
        for(int i=x; i<=n; i+=Lowbit(i))c[i]+=v;
    }
    BigInteger sum(int x) { //求出1~x的区间和 
        BigInteger s=0;
        for(int i=x; i; i-=Lowbit(i))s+=c[i];
        return s;
    }
} bit;
int n,a[50005],b[50005];
BigInteger f[50005],ans;
void Calc(int x) { //统计x元组 
    bit.init(n);
    bit.add(b[x-1],f[x-1]); //先加个1进去 
    f[x-1]=0;
    for(int i=x; i<=n; i++) { 
        bit.add(b[i],f[i]); //丢进树状数组 
        f[i]=bit.sum(b[i]-1); //统计比他小的 
    }
}
map<int,int>M;
map<int,int>::iterator it;
void Discretization() { //a是待离散数组 b是离散后数组.
    M.clear();
    memset(b,0,sizeof(b));
    for(int i=1; i<=n; i++)M[a[i]]=1; 
    int i=1;
    for(it=M.begin(); it!=M.end(); it++,i++)it->second=i;
    for(int i=1; i<=n; i++)b[i]=M[a[i]];
}
int main() {
    n=Get_Int();
    for(int i=1; i<=n; i++) {
        a[i]=Get_Int();
        f[i]=1;
    }
    Discretization();
    for(int i=2; i<=5; i++)Calc(i);
    for(int i=5; i<=n; i++)ans+=f[i];
    cout<return 0;
}

你可能感兴趣的:(树状数组)