洛谷
依次为曼哈顿距离,欧式距离的公式。
公式化简一下 就知道,我们要找 横坐标相等 或者 纵坐标相等的 一对点。
所以开两个map,一个记录横坐标的个数,一个记录纵坐标的个数。遍历点。
对于每一个点
ans += mp1[ve[i].first];
ans += mp2[ve[i].second];
mp1[ve[i].first]++;
mp2[ve[i].second]++;
这里的意思是 ,(x,y)会和前面 横坐标相同的点 组成一对,会和前面纵坐标相同的点 组成一对。但是对于 坐标相同的点,我们重复计算了,所以还要再开一个map,记录重复坐标的点的数量和信息。
最后减去,多加的就可以了。
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n; cin >> n;
vector<pair<int, int>>ve(n);
//点的坐标
int ans = 0;
map<int, int>mp1;
map<int, int>mp2;
map<pair<int, int>, int>mp3;
int cnt = 0;
for (int i = 0; i < n; i++)
{
cin >> ve[i].first;
cin >> ve[i].second;
mp3[{ve[i].first,ve[i].second}]++;
ans += mp1[ve[i].first];
ans += mp2[ve[i].second];
mp1[ve[i].first]++;
mp2[ve[i].second]++;
}
这里自己模拟一下,公式就推出来了
for (auto i : mp3)
{
if (i.second > 1)
{
cnt += i.second * (i.second - 1) / 2;
}
}
//减去两个点完全相同的个数。
cout << ans - cnt << "\n";
}
当然也可以 直接在遍历点的时候,处理重复点的信息。
这个也许 更简单一点?
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n; cin >> n;
vector<pair<int, int>>ve(n);
//点的坐标
int ans = 0;
map<int, int>mp1;
map<int, int>mp2;
map<pair<int, int>, int>mp3;
int cnt = 0;
for (int i = 0; i < n; i++)
{
cin >> ve[i].first;
cin >> ve[i].second;
ans += mp1[ve[i].first];
ans += mp2[ve[i].second];
ans-=mp3[{ve[i].first,ve[i].second}];
mp1[ve[i].first]++;
mp2[ve[i].second]++;
mp3[{ve[i].first,ve[i].second}]++;
}
cout << ans << "\n";
}
codeforce 946 C
n个数字,定义了三元组,
询问有多少美丽对。也是容斥。
#include <bits/stdc++.h>
void solve()
{
int n;
std::cin >> n;
std::vector<int>a(n);
for (int i = 0; i < n; i++)
std::cin >> a[i];
long long ans = 0;
//两个三元组美丽,就是 只差一个。那么他们可能是ab ac bc位置是相同的。
// 对于 每一个位置开一个map
//枚举三元组的位置,例如abc
//依次枚举了 ab ac bc
//实际上 是分别枚举了 每一个三元组的 ab ac bc位置
for (int x=0;x<3;x++)
for (int y = x + 1; y < 3; y++) {
std::map<std::pair<int, int>, int>cnt;
for (int i = 0; i + 2 < n; i++) {
//std::cout << a[i + x] << " " << a[i + y] << "\n";
//每一次碰到 这个二元有序,她可以和前面的 美丽
ans += cnt[{a[i + x], a[i + y]}];
cnt[{a[i + x], a[i + y]}]++;
}
}
//减去三个字符都相等的情况
std::map<std::tuple<int, int, int>, int>cnt;
for (int i = 0; i + 2 < n; i++)
{
ans -= 3*cnt[{a[i], a[i + 1], a[i + 2]}];
cnt[{a[i], a[i + 1], a[i + 2]}]++;
}
std::cout << ans << "\n";
}
int main()
{
std::cin.tie(nullptr)->sync_with_stdio(false);
int t; std::cin >> t;
while (t--)
{
solve();
}
return 0;
}