ABC 252 | D - Distinct Trio
题意
给定含有N个元素的数组A,输出满足下列条件的三元组的数量。
- 各不相同
分析
对于数对计数问题,常用的方法是枚举其中某一个数,然后快速计算选定该数的情况下满足条件的数对个数。由于枚举某个数的复杂度为,所以一般情况下,计算选定该数后满足条件的数组对数的复杂度为。为达到快速计算的目的,通常需要预处理出某些值,预处理的手段一般有动态规划、前缀和等,此外,部分项应合并处理。
以下两种方法枚举不同的数值,对应不同的预处理方法。
方法一
根据题意,枚举的大小,然后计算对于当前,满足条件的的组数,该步骤分析用到了容斥原理。
下面分别计算上式中各项的值。
- ,可理解为在之前选一个与之相等的,有个,然后再选一个与不等的,有个,将两个数中下标小的自动赋值给,下标大的自动赋值给
- 需要用来维护,以表示前个数中任选两个且这两个数相等的方案数,那么有表示前中与相等的数的个数。
- 表示之前等于的数的个数
方法二
首先转化题意,寻找三元组使得各不相同,等价于寻找三元组。对于后者,我们可以遍历中间大小的数,对于每一个确定的,对应的三元组个数为,可以通过预处理出前缀和从而得到。
对于二者的等价性可作如下理解:
- 首先证明每一个都对应一组,由于所找各不相同,所以可以得到三个互不相同的数组下标,按照大小顺序排好即得。
- 其次证明每一个对应一个,不难发现可能存在多对一的情况,举例来说,与可能对应同一组,这意味着我们在遍历时,对于是对整个数组进行for循环,相同的数值会被重复计算,同理考虑不同的对应同一与不同的对应同一的情况,发现按照以上算法该情况被正确计算
故以上两种表示等价且算法正确。
注意: 计数类问题可能需要开long long。
代码
方法一
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n;
ll a[N], f[N];
ll mp[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
ll ans = 0;
for(int i = 1; i <= n; i ++){
int x = a[i];
ans += (ll)(i - 1) * (i - 2) / 2;
ans -= mp[x] * (i - 1 - mp[x]);
ans -= f[i - 1];
f[i] = f[i - 1] + mp[x];
mp[x] ++;
}
printf("%lld\n", ans);
return 0;
}
方法二
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
int a[N];
int n;
ll cnt[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
int x;
scanf("%d", &x);
a[i] = x;
cnt[x] ++;
}
for(int i = 1; i < N; i ++) cnt[i] = cnt[i - 1] + cnt[i];
ll ans = 0;
for(int i = 1; i <= n; i ++) {
int t = a[i];
ans += cnt[t - 1] * (n - cnt[t]);
}
printf("%lld\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库