UVA1428 Ping pong 题解
虽然用的都是树状数组, 但我的方法似乎和其他题解有点不太一样(
简化题意, 将题目转化为这个问题:
给定一个数列 \(s\), 求在\(s\)中有多少组数\((a,b,c)\)满足\(a<b<c\)且\(s_a<s_b<s_c\)或\(s_a>s_b>s_c\)
对\(s_a<s_b<s_c\)和\(s_a>s_b>s_c\)的情况分别讨论.
可以发现, 解决有多少组数\((a,b,c)\)满足\(s_a>s_b>s_c\)这个问题只要把\(s\)顺序颠倒过来再算满足\(s_a<s_b<s_c\)的数量就可以了.
而算\(s_a<s_b<s_c\)的数量, 可以先算满足\(a<b\)且\(s_a<s_b\)的数量, 再算满足\(b<c\)且\(s_b<s_c\)的数量(程序实践的时候可以在一起计算).这需要用到树状数组, 具体的说明可以参考这道题的题解, 这里不再赘述.
有一个地方需要注意, 就是 rank 这个名字在 C++ 的某个头文件里被用过, 但洛谷的编译器是不会触发 CE 的, 而在 UVA 中会 CE.
下面贴上代码.
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#define ll long long
#define lowbit(x) x & (-x)
using namespace std;
struct NODE {
int val, id;
} a[20003], b[20003];
inline bool cmp (const NODE &x, const NODE &y) {
return x.val == y.val ? x.id > y.id : x.val < y.val;
}
int n, ranks[20003], score[20003], c[20003], d[20003];
inline int query(int x, int *c) {
int ans = 0;
while (x)
ans += c[x], x -= lowbit(x);
return ans;
}
inline void add (int x, int y, int *c) {
while (x <= n)
c[x] += y, x += lowbit(x);
return;
}
inline ll sovle() {
memset(c, 0, sizeof(c));
memset(d, 0, sizeof(d));
memset(score, 0, sizeof(score));
ll ans = 0;
for (int i = 1; i <= n; i++)
ranks[b[i].id] = i; // 第 i 个数的排名
for (int i = 1; i <= n; i++) { // 注意 for 里面用的都是 ranks[i]
// 计算 a < b 且 s[a] < s[b] 的情况
score[ranks[i]] = query(ranks[i] - 1, c);
add(ranks[i], 1, c);
// 计算 b < c 且 s[b] < s[c] 的情况
ans += query(ranks[i] - 1, d);
add(ranks[i], score[ranks[i]], d);
}
return ans;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i].val), a[i].id = i;
sort(a + 1, a + n + 1, cmp);
ll ans = 0;
for (int i = 1; i <= n; i++)
b[i] = a[i];
ans += sovle();
for (int i = 1; i <= n; i++)
b[i] = a[n - i + 1];
ans += sovle(); // 反过来再算
printf("%lld\n", ans);
}
return 0;
}
语文不好, 表述的可能不是很清楚.
( ゚∀゚)o彡゜ ヒーコー ヒーコー!

浙公网安备 33010602011771号