• 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 }
  • 相关阅读:
    20135326、20135303linux实验二实验报告
    家庭作业汇总
    信息安全系统设计基础第十周学习总结
    信息安全系统设计基础第十二周总结
    20135326王亦可信息安全系统设计基础期末总结
    第十一周学习总结
    20135326、20135303linux实验四实验报告
    20135326、20135303linux实验一实验报告
    第十四周学习笔记
    20135326、20135303linux实验三实验报告
  • 原文地址:https://www.cnblogs.com/jrfr/p/10739686.html
Copyright © 2020-2023  润新知