zoukankan      html  css  js  c++  java
  • HDU 4334 Trouble

    http://acm.hdu.edu.cn/showproblem.php?pid=4334

    这题首先想到的就是穷举每一行中的数字,相加看是否为0 。 ----别傻了,n5 的循环,等着超时吧!

         现在要做的事如何缩减循环次数。先枚举头两行相加的可能结果,发现有些数的和是重复的!也就是说,可能会有多余的循环存在。
    于是可以先计算出头两行的所以和结果,再去重,再计算3、4行的和结果、去重,拿前面得到的两个数组再和最后一行枚举相加判断就
    能得到结果。这样复杂度变为n3快了,但是还不够。可以再把之前得到的两个新数组排序下,枚举第5行,对于每次枚举,两个排序后的
    数组,一个从小到大,一个从大到小查找,发现相加结果比0大,就把大的数组往小的方向移(如果要移小的数组,只可能增大结果)。
    发现相加结果比0小,就把小的数组往大的方向移。可以AC了。

      还有一种方法就是哈希。把头两行的所有和结果记录下来,可以设个数组初始为0,当出现一个和是,就把数组中下标为和的元素置1.
    枚举后三行的所有和结果,发现存在和的负数为下标(下标当然有个偏移量,怎么可能为负)在数组中为1,则说明满足条件。
    新的问题是数组开1015是会爆的,所以用取模哈希,为了处理哈希值重复的情况,每个数组元素都要接个链表,记录哈希重复的不同数值。

    排序法:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include<algorithm>
     4 using namespace std;
     5 long long a[5][205];
     6 int hb(long long *a,long long *b,int na,int nb,long long *&t)
     7 {
     8     long long *temp=new long long[na*nb+1];
     9     int nn=0;
    10     for (int i=0;i<na;++i)
    11      for (int j=0;j<nb;++j)
    12        temp[nn++]=a[i]+b[j];
    13     sort(temp,temp+nn);
    14     nn = unique(temp,temp+nn)-temp;
    15     t=temp;
    16     return nn;
    17 }
    18 int main()
    19 {
    20     int T;
    21     scanf("%d",&T);
    22     while (T--)
    23     {
    24         int n;
    25         scanf("%d",&n);
    26         for (int i=0;i<5;++i)
    27          for (int j=0;j<n;++j) scanf("%I64d",&a[i][j]);
    28          long long *t1,*t2;
    29          int n1,n2;
    30          n1=hb(a[0],a[1],n,n,t1);
    31          n2=hb(a[2],a[3],n,n,t2);
    32          bool fla=false;
    33          for (int i=0;i<n&&!fla;++i)
    34          {
    35              int x=0,y=n2-1;
    36              register long long tt=a[4][i];
    37              while (x<n1 && y>=0)
    38              {
    39                  if (t1[x]+t2[y]+tt>0) --y;
    40                  if (t1[x]+t2[y]+tt<0) ++x;
    41                  if (t1[x]+t2[y]+tt==0) {fla=true;break;}
    42              }
    43          }
    44          if (fla) printf("Yes\n"); else printf("No\n");
    45          delete []t1;delete []t2;
    46     }
    47 }

    哈希法:

     1 #include <stdio.h>
     2 #include <string.h>
     3 long long a[5][205];
     4 long long v[90000];
     5 int h[1000020],hn,ne[90000];
     6 int hash(long long  sum)
     7 {
     8     int k;
     9     if(sum>0) k=(int)(sum %  1000007);
    10        else k=(int)(-sum % 1000007);
    11     return k ;
    12 }
    13 void add(int k,long long sum)
    14 {
    15     v[hn] = sum;
    16     ne[hn] = h[k];
    17     h[k] =hn++;
    18 }
    19 
    20 int main()
    21 {
    22     int T;
    23     scanf("%d",&T);
    24     while (T--)
    25     {
    26         int n;
    27         scanf("%d",&n);
    28         for (int i=0;i<5;++i)
    29          for (int j=0;j<n;++j) scanf("%I64d",&a[i][j]);
    30          hn=0;
    31         for (int i=0;i<1000020;++i) h[i]=-1;
    32         bool fla=false;
    33         for (int q1=0;q1<n&&!fla;++q1)
    34         for (int q2=0;q2<n&&!fla;++q2)
    35         {
    36             long long s=a[0][q1]+a[1][q2];
    37             add(hash(s),s);
    38         }
    39         for (int q3=0;q3<n&&!fla;++q3)
    40         for (int q4=0;q4<n&&!fla;++q4)
    41         for (int q5=0;q5<n&&!fla;++q5)
    42         {
    43             long long s=a[2][q3]+a[3][q4]+a[4][q5];
    44             for (int x=h[hash(-s)];x!=-1;x=ne[x])
    45             {
    46                 if (s+v[x]==0) {fla=true;break;}
    47             }
    48         }
    49         if (fla) printf("Yes\n"); else printf("No\n");
    50     }
    51 
    52 }

    这题之前WA了好几次,思路是对的,就错在细节上:

      1)输入储存数组的范围开小了,认为每行最多50个数~

      2)用qsort()时,比较函数cmp 返回的是int ,但我拿两个long long 的差来返回,高位截断,排序就不对了

  • 相关阅读:
    1265 四点共面
    1003 阶乘后面0的数量
    1080 两个数的平方和
    1090 3个数和为0
    1087 1 10 100 1000
    1082 与7无关的数
    OpenLayers工作原理
    CI(持续集成)CD(持续交付)
    打包命令
    文件与目录管理重点
  • 原文地址:https://www.cnblogs.com/wuminye/p/2796428.html
Copyright © 2011-2022 走看看