在线评测链接:P1083
在一个小镇上,有一家古董店。这家古董店主人是一个极具收藏热情的老人,他一生都在收集和珍藏各种珍奇古董。他把他的珍藏分成了许多类别,其中包括了各种古代文物、稀有的艺术品和珍贵的文献资料等。
然而,这位老人在年轻时曾有一段失恋的经历,他的爱人因意外离世,让他深受打击。他渐渐地迷上了麻将这项运动,麻将成为了他减轻痛苦的一种方式。他甚至在自己的古董店里开了一间麻将室,邀请各位朋友前来打麻将。
一天,他在整理古董时发现了一组古董,这组古董是他年轻时收藏的。他把这些古董拿到麻将室,让朋友们来观赏和欣赏。这组古董是由 n n n 个不同的古董组成的,老人和他的朋友们都非常喜欢这些古董。
他在整理这些古董时,发现了一组数字序列 a 0 , a 1 , ⋯ , a n − 1 a_0,a_1,\cdots,a_{n-1} a0,a1,⋯,an−1 ,其中每个 a i a_i ai 表示古董的编号。
他想让朋友们玩一下游戏,要求朋友们找出有多少组三元组 < i , j , k > < i,j,k > <i,j,k> 满足 0 ≤ i < j < k < n 0\le i
这时,老人问你是否能够帮助他计算出答案。
第一行输入一个正整数 n n n 。
第二行输入 n n n个正整数 a i a_{i} ai 。
3 ≤ n ≤ 200000 3 \leq n \leq 200000 3≤n≤200000
1 ≤ a ≤ 1 0 9 1 \leq a \leq 10^9 1≤a≤109
一个整数,代表合法的三元组数量。
输入
5
3 2 1 2 3
输出
5
输入
5
1 2 3 4 5
输出
0
观察 m a x − m i n = 1 max - min = 1 max−min=1,那么三元组中 必定有两个元素相等 ,结构如下两种
情况1 x − 1 , x , x x-1,x,x x−1,x,x
情况2 x − 1 , x − 1 , x x-1,x-1,x x−1,x−1,x
那么我们可以使用一个桶(哈希表) d d d先统计每个数出现的次数。然后枚举每一个值 x x x.
第一种情况的贡献: C ( d [ x ] , 2 ) ∗ d [ x − 1 ] C(d[x] , 2) * d[x-1] C(d[x],2)∗d[x−1]
第二种情况的贡献: C ( d [ x − 1 ] , 2 ) ∗ d [ x ] C(d[x-1] , 2) * d[x] C(d[x−1],2)∗d[x]
累加起来即可.答案是 n 3 n^3 n3 级别的,记得开 l o n g l o n g long\ long long long
塔子哥点评:今年春招考了很多这种计数题。80%出自牛客出题组之手(阿里,百度,蚂蚁,携程…).这类题在OI/ACM界一般也称作数数题
以下都是23春招考察到的数数题,难度依次递增
P1133 京东 2023.03.28-第二题-染色の数组
P1192 2023.04.13-腾讯音乐-暑期实习-第一题-平滑值
P1104 2023.03.21-阿里-第五题-任务分配
P1055 2023.2.25-京东-塔子哥的单词
P1099 2023.03.21-蚂蚁-第三题-塔子哥的排列权值之和
P1096 2023.03.19-米哈游-第三题-倍数集合
P1243 2023.04.20-蚂蚁暑期实习-第二题-RB字符串
P1126 2023.03.26-实习-腾讯-第五题-序列最大公约
#include
using namespace std;
#define ll long long
unordered_map<int , ll> d;
int main() {
int n;
cin >> n;
ll ans = 0;
// 读入 + 桶计数
for (int i = 1 ; i <= n ; i++){
int x;
cin >> x;
d[x]++;
}
// 公式参考上面
for (auto g : d){
int x = g.first;
ans += (d[x] - 1) * d[x] / 2 * d[x - 1];
ans += (d[x - 1] - 1) * d[x - 1] / 2 * d[x];
}
cout << ans << endl;
return 0;
}
import collections
d = collections.defaultdict(int)
n = int(input())
ans = 0
# 读入 + 桶计数
for x in map(int,input().split()):
d[x] += 1
# 公式参考上面
for x in sorted(d.keys()):
ans += (d[x] - 1) * d[x] // 2 * d[x - 1]
ans += (d[x - 1] - 1) * d[x - 1] // 2 * d[x]
print(ans)
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n = input.nextInt();
Map<Integer, Long> d = new HashMap<>();
long ans = 0;
// 读入 + 桶计数
for (int i = 1 ; i <= n ; i++){
int x = input.nextInt();
d.put(x, d.getOrDefault(x, 0L)+1L);
}
// 公式参考上面
for (Map.Entry<Integer, Long> entry : d.entrySet()) {
int x = entry.getKey();
long value = entry.getValue();
if (d.containsKey(x-1)) {
ans += (value - 1) * value / 2 * d.get(x-1);
}
if (d.containsKey(x+1)) {
ans += (value - 1) * value / 2 * d.get(x+1);
}
}
System.out.println(ans);
}
}
package main
import (
"fmt"
"sort"
)
func main() {
var n int
fmt.Scan(&n)
d := make(map[int]int64)
ans := int64(0)
// 读入 + 桶计数
for i := 1; i <= n; i++ {
var x int
fmt.Scan(&x)
d[x] += 1
}
// 公式参考上面
keys := make([]int, 0)
for k := range d {
keys = append(keys, k)
}
sort.Ints(keys)
for _, x := range keys {
if cnt, ok := d[x]; ok && cnt > 1 {
ans += (cnt - 1) * cnt / 2 * d[x-1]
}
if cnt, ok := d[x-1]; ok && cnt > 1 {
ans += (cnt - 1) * cnt / 2 * d[x]
}
}
fmt.Println(ans)
}
process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
input += data;
return;
});
process.stdin.on('end', () => {
const lines = input.trim().split('\n');
let d = new Map();
let ans = 0;
let n = parseInt(lines[0]);
// 读入 + 桶计数
lines[1].trim().split(' ').forEach((x) => {
x = parseInt(x)
if (d.has(x)) {
d.set(x, d.get(x) + 1);
} else {
d.set(x, 1);
}
});
// 公式参考上面
let keys = [...d.keys()].sort((a, b) => a - b);
for (let i = 0; i < keys.length; i++) {
let x = keys[i];
// 因为x - 1不一定存在
let tmp = d.get(x - 1) || 0;
ans += (d.get(x) - 1) * d.get(x) / 2 * tmp;
ans += (tmp - 1) * tmp / 2 * d.get(x);
}
console.log(ans);
});