hihocoder 1505

hihocoder 1505

题意:给你n个数,让你从n个数中抽两个数,再抽两个数,使得前两个数和后两个数相等

 

分析:对 i,j,p,q遍历的话时间复杂度会达到o(n4),所以考虑优化p,q

  

假设分配给小hi的金币为 a[i]和a[j],现在的问题是求剩下的元素中有多少组 p, q 使得 a[i] + a[j] = a[p] + a[q]。如果暴力枚举所有可能的 p, q,需要 O(n^2)时间,再加上枚举i, j 的时间,时间复杂度是 O(n^4),会超时。所以不能枚举 p, q。

把输入保存在数组 a[] 中。

令 sumCnt[x] 表示两袋金币之和 a[i] + a[j] = x 组合数。

令 cnt[y] 表示元素 y 出现的次数。

假设分配给小hi的金币为 x = a[i] + a[j],那么x一共有 sumCnt[x] 种可能的组合。

令 c1 = cnt[a[i]], c2 = cnt[a[j]],

假设 a[i] != a[j]。

去掉a[i], a[j]之前,a[i]和a[j]一共可以组成 c1 * c2个 x。去掉 a[i] 后,还有 c1 - 1个与 a[i] 相同的元素,去掉 a[j] 后,还有 c2 - 1 个与 a[j] 相同的元素,它们还可以组成 (c1 - 1) * (c2 - 1) 个 x。

所以,如果分配给小hi的金币为 a[i]和a[j],那么存在 sumCnt - (c1 * c2 - (c1 - 1) * (c2 - 1)) 对 p, q 使得 a[i] + a[j] = a[p] + a[q]。

当 a[i] == a[j] 时,也是类似的处理。

现在,求p, q的组数只需要 O(1),总的时间复杂度是 O(n^2)。

如果不考虑非法组合的话, 辣么 对于 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个数。

1:v[

2;sumcnt[v[i]+v[j]]函数是存储sum=v[i]+v[j]的个数

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 #include <map>
 7 #include <iomanip>
 8 #include <algorithm>
 9 #include <queue>
10 #include <stack>
11 #include <set>
12 #include <vector>
13 //const int maxn = 1e5+5;
14 #define ll long long
15 #define MAX INT_MAX
16 #define FOR(i,a,b) for( int i = a;i <= b;++i)
17 using namespace std;
18 int v[1100],cnt[1100000],sumcnt[2100000];
19 ll n,ans;
20 int main()
21 {
22        //    freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
23     //    freopen("D:\\common_text\\code_stream\\out.txt","w",stdout);
24     cin>>n;
25     FOR(i,1,n)
26     {
27         cin>>v[i];
28         cnt[v[i]]++;
29     }
30     for(int i=1;i<=n-1;++i)
31     {
32         for(int j=i+1;j<=n;++j)
33         {
34             sumcnt[v[i]+v[j]]++;
35         }
36     }
37     for(int i=1;i<=n-1;++i)
38     {
39         for(int j=i+1;j<=n;++j)
40         {
41             if(v[i]!=v[j])
42             {
43                 ans+=sumcnt[v[i]+v[j]]-cnt[v[i]]-cnt[v[j]]+1;    
44             }
45             else
46             {
47                 ans+=sumcnt[v[i]+v[j]]-(cnt[v[i]]-1)-(cnt[v[j]]-1)+1;    //这两个看不懂很正常,一定要在纸上自己画画,重叠部分+1,想法也可以不唯一,化简后还是一样的
48             }
49         }
50     }
51     cout<<ans<<endl;
52 }

 

posted @ 2019-04-20 01:12  阿斯水生产线  阅读(182)  评论(0编辑  收藏  举报