题目名称:小Hi和小Ho的礼物
题目链接:
描述
某人有N袋金币,其中第i袋内金币的数量是Ai。现在他决定选出2袋金币送给小Hi,再选2袋金币送给小Ho,同时使得小Hi和小Ho得到的金币总数相等。他想知道一共有多少种不同的选择方法。
具体来说,有多少种下标四元组(i, j, p, q)满足i, j, p, q两两不同,并且i < j, p < q, Ai + Aj = Ap + Aq。
例如对于数组A=[1, 1, 2, 2, 2],一共有12种选法:
i j p q
1 3 2 4
1 3 2 5
1 4 2 3
1 4 2 5
1 5 2 3
1 5 2 4
2 3 1 4
2 3 1 5
2 4 1 3
2 4 1 5
2 5 1 3
2 5 1 4
输入
第一行包含一个整数N。
第二行包含N个整数,
A
1
,
A
2
,
A
3
.
.
.
A
N
。
A_1, A_2, A_3 ... A_N。
A1,A2,A3...AN。
对于70%的数据,1 <= N <= 100
对于100%的数据,1 <= N <= 1000, 1 <= A i A_i Ai <= 1000000
输出
不同选择的数目
样例输入
5
1 1 2 2 2
样例输出
12
思路
参考讨论给出的思路,使用HASH+容斥原理技术解决问题
代码
#include<bits/stdc++.h>
using namespace std;
#define N 2000020
int f[N],g[N],A[N];
long long ans;
int n;
int main()
{
ans=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>A[i];
g[A[i]]++;
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
f[A[i]+A[j]]++;
}
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(A[i]==A[j]) ans+=f[A[i]+A[j]]-2*g[A[i]]+3;
else ans+=f[A[i]+A[j]]-g[A[i]]-g[A[j]]+1;
}
}
cout<<ans<<endl;
return 0;
}
当然这么写有点浪费空间,可以结合map函数改进
#include<bits/stdc++.h>
using namespace std;
#define N 1010
int A[N];
map<int,int> f,g;
long long ans;
int n;
int main()
{
ans=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>A[i];
g[A[i]]++;
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
f[A[i]+A[j]]++;
}
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(A[i]==A[j]) ans+=f[A[i]+A[j]]-2*g[A[i]]+3;
else ans+=f[A[i]+A[j]]-g[A[i]]-g[A[j]]+1;
}
}
cout<<ans<<endl;
return 0;
}