1. 程式人生 > >P1637 三元上升子序列

P1637 三元上升子序列

輸入輸出 names ac代碼 span mes != || while bad

題目描述

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 三元上升子序列