P1637 三元上升子序列

Posted alex-leaves

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1637 三元上升子序列相关的知识,希望对你有一定的参考价值。

 题目描述

Erwin最近对一种叫"thair"的东西巨感兴趣。。。

在含有n个整数的序列a1,a2......an中,

三个数被称作"thair"当且仅当i<j<k且ai<aj<ak

求一个序列中"thair"的个数。

输入输出格式

输入格式:

开始一个正整数n,

以后n个数a1~an。

 

输出格式:

"thair"的个数

 

输入输出样例

输入样例#1: 复制
4
2 1 3 4
输出样例#1: 复制
2
输入样例#2: 复制
5
1 2 2 3 4
输出样例#2: 复制
7

说明

对样例2的说明:

7个"thair"分别是

1 2 3 1 2 4 1 2 3 1 2 4 1 3 4 2 3 4 2 3 4 约定 30%的数据n<=100

60%的数据n<=2000

100%的数据n<=30000

大数据随机生成

0<=a[i]<=maxlongint

 

其实就是求逆序对,设ans1为之前比他小的数的个数,ans2为大的个数,显然ans+=ans1*ans2.

我们看到这数据规模,不能用桶,得离散化一下……然后常规操作。

AC代码如下:

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=30000+5;
struct p{
    int id,num;
    bool operator < (const p &aa) const{
    return num<aa.num;}
}a[N];
int ans1[N],ans2[N],n,c[N],pos[N],now;
long long ans;
int sum(int x)
{
    int res=0;
    while(x>0) res+=c[x],x-=(x&-x);
    return res;
}
void add(int x)
{
    while(x<=n) c[x]++,x+=(x&-x);
    return; 
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i].num),a[i].id=i;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
     pos[a[i].id]=((a[i].num!=a[i-1].num)||i==1)?i:pos[a[i-1].id];
    for(int i=1;i<=n;i++)
    now=pos[i],ans1[i]=sum(now-1),add(now);
    fill(c+1,c+n+1,0);
    for(int i=n;i>0;i--)
    now=pos[i],ans2[i]=sum(n-now),add(n-now+1);
    for(int i=1;i<=n;i++)
    ans+=ans1[i]*ans2[i];
    printf("%lld",ans);
    return 0;
}

以上是关于P1637 三元上升子序列的主要内容,如果未能解决你的问题,请参考以下文章

P1637 三元上升子序列

P1637 三元上升子序列

洛谷 P1637 三元上升子序列Treap

Luogu P1637 三元上升子序列

Luogu P1637 三元上升子序列权值线段树By cellur925

『Luogu 1637』三元上升子序列 (树状数组)