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

洛谷P1637 三元上升子序列

print tput cst inpu i++ left style 格式 而不是

P1637 三元上升子序列

  • 48通過
  • 225提交
  • 題目提供者該用戶不存在
  • 標簽雲端
  • 難度提高+/省選-
  • 時空限制1s / 128MB

提交 討論 題解

最新討論更多討論

  • 為什麽超時啊
  • a的數據比較大啊,真的能用…

題目描述

Erwin最近對一種叫"thair"的東西巨感興趣。。。

在含有n個整數的序列a1,a2......an中,

三個數被稱作"thair"當且僅當i<j<k且ai<aj<ak

求一個序列中"thair"的個數。

輸入輸出格式

輸入格式:

開始一個正整數n,

以後n個數a1~an。

輸出格式:

"thair"的個數

輸入輸出樣例

輸入樣例#1

Input

4

2 1 3 4

Output

2

Input

5

1 2 2 3 4

Output

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

輸出樣例#1

說明

約定 30%的數據n<=100

60%的數據n<=2000

100%的數據n<=30000

大數據隨機生成

0<=a[i]<=maxlongint

分析:這道題可以借鑒之前求逆序對那樣求,我們只需要求對於每一個數i,在i之前比i小的數的個數和在i之後比i大的數的個數,相乘起來,最後將所有結果加起來就是答案,關鍵就是如何求出這些數的個數。可以利用樹狀數組。先將數據離散化,先找小於i的,因為要嚴格小於,所以我們要先-1再查找,然後添加進去,然後找大於i的,從後往前枚舉,相當於我們找到i之後不大於i的個數,然後用n-i(i之後的數的個數)減去結果就是嚴格大於i的數的個數,最後統計一下答案即可。

如果將這道題推廣到要找k個數的情況,我們需要用到dp,則dp[i][j] = dp[k][j-1] + dp[k][j],其中k為小於i中最靠後的一個數.

#include <iostream>  
#include <cstdlib>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <algorithm>
#include <queue>
#include <stack>
#include 
<cmath> using namespace std; long long d1[30010], d2[30010],ans1[30010],ans2[30010],dis[30010],ans; struct node { long long v; int id; }a[30010]; int n; void update(long long x, int v) { while (x <= n) { d1[x] += v; x += x &(-x); } } int sum(long long x) { int cnt = 0; while (x) { cnt += d1[x]; x -= x & (-x); } return cnt; } void update2(long long x, int v) { while (x <= n) { d2[x] += v; x += x &(-x); } } int sum2(long long x) { int cnt = 0; while (x) { cnt += d2[x]; x -= x & (-x); } return cnt; } bool cmp(node a, node b) { return a.v < b.v; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i].v); a[i].id = i; } sort(a + 1, a + 1 + n, cmp); dis[a[1].id] = 1; int tot = 1; for (int i = 2; i <= n; i++) { if (a[i].v != a[i - 1].v) tot++; dis[a[i].id] = tot; } for (int i = 1; i <= n; i++) { ans1[i] = sum(dis[i] - 1); //是找嚴格小於的而不是小於等於的 update(dis[i], 1); } for (int i = n; i >= 1; i--) { ans2[i] = n - i - sum2(dis[i]); update2(dis[i], 1); } for (int i = 1; i <= n; i++) ans += ans1[i] * ans2[i]; printf("%lld\n", ans); return 0; }

洛谷P1637 三元上升子序列