某人有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
Input
第一行包含一个整数N。
第二行包含N个整数,A1, A2, A3 ... AN。
对于70%的数据,1 <= N <= 100
对于100%的数据,1 <= N <= 1000, 1 <= Ai <= 1000000
Output
不同选择的数目。
Sample Input
5 1 1 2 2 2
Sample Output
12
题意:中文题...
思路:因为每次都是拿出来两个,所以我们可以先求一下,每一次拿出来两袋的和,并记录这个和出现次数。然后我i们再枚举一次 i ,j ,此时我们就可以直接知道这个和出现的次数。但是里面肯定有很多重复的,所以我们要记录一下每个数出现的次数。然后分情况讨论
1.num[i] ! = num[j] eg: 1 1 2 2 2
如果我们现在枚举的是 1,3号点(红线),算出和为3.但是我们第一次枚举的和为3的所有情况,记个数为 temp;
又因为另外一组的不能拿1和3号点,所以我们要减去2的个数(蓝线),因为 1(此时 i 的位置上的值)+2 =3。我们再看一眼上图,2号点和3号点也相连了(紫虚线),所以我们还要把以二号点为终点的所有线给去掉,也就是再减去 1 的个数。然后我发现1->3 这条线减了两次,因此我们要加 +1. 。综合 t = v[sum] - u[ num[i] ]] - u[ num [j] ] + 1;
2. num[i] = = num[j] eg: 1 1 1 1 1
同理 t = v[sum] - u[ num[i] ]] - u[ num [j] ] + 3;
综上 :1. num[i] = = num[j] t = v[sum] - u[ num[i] ]] - u[ num [j] ] + 3;
2.num[i] ! = num[j] t = v[sum] - u[ num[i] ]] - u[ num [j] ] + 1;
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
map<ll,int>v,u;
ll num[10010];
int main()
{
int n;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%lld",&num[i]);
u[num[i]]++;
}
sort(num,num+n);
int q=1;
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++)
{
ll x=num[i]+num[j];
v[x]++;
}
ll ans=0;
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++)
{
ll x=num[i]+num[j];
ll t;
if(num[i]==num[j])
t=v[x]-u[num[j]]-u[num[i]]+3;
else
t=v[x]-u[num[j]]-u[num[i]]+1;
if(t>0)ans+=t;
}
printf("%lld\n",ans);
return 0;
}