描述
某人有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个整数,A1, A2, A3 … AN。
对于70%的数据,1 <= N <= 100
对于100%的数据,1 <= N <= 1000, 1 <= Ai <= 1000000
输出
不同选择的数目。
样例输入
5
1 1 2 2 2
样例输出
12
如果不考虑非法组合的话, 辣么 对于 a[i] + a[j] = a[q] + a[p] = M。 假如 有x 对 a[i] + a[j] = M 的话,答案就是 C(m,2).
考虑重复。 举个栗子, 对于序列, 1 1 2 2 2。 当你M = 3,选择(1,3)(下标)时,你再选择其他(a[q],a[p])的情况,你要去掉 下标(1,4,)(1,5)(3,2)。 也就是 包含(1,3)中某一个的情况。可以发现有 (n+m-2)n为1个数,m为3个数。
#include <iostream>
#include <cstring>
#include <map>
using namespace std;
const int maxn = 1e5+50;
#define FCIN ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
const int MAXINT = 0x7fffffff;
const int MININT = 0x80000000;
typedef long long LL;
int a[maxn];
int cou[10*maxn];
map<int,int> M;
int main(int argc, char* argv[] ){
FCIN;
int n; cin>>n;
M.clear();
memset(cou,0,sizeof(cou));
for(int i=1;i<=n;i++) cin>>a[i],cou[a[i]]++;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
M[ a[i]+ a[j] ]++;
}
}
LL ans = 0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i] != a[j]){
ans += M[ a[i] + a[j] ] - (cou[a[i]] + cou[a[j]] -2) -1 ;
}
else{
ans += M[ a[i] + a[j] ] - (cou[a[i]] + cou[a[j]] -4) - 1;
}
}
}
cout<<ans<<endl;
return 0;
}