HDU 4334Trouble(2012多校第四场D题 合并堆分治)

Trouble

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3784    Accepted Submission(s): 1187


Problem Description
Hassan is in trouble. His mathematics teacher has given him a very difficult problem called 5-sum. Please help him.
The 5-sum problem is defined as follows: Given 5 sets S_1,...,S_5 of n integer numbers each, is there a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0?
 

Input
First line of input contains a single integer N (1≤N≤50). N test-cases follow. First line of each test-case contains a single integer n (1<=n<=200). 5 lines follow each containing n integer numbers in range [-10^15, 1 0^15]. I-th line denotes set S_i for 1<=i<=5.
 

Output
For each test-case output "Yes" (without quotes) if there are a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0, otherwise output "No".
 

Sample Input
   
   
   
   
2 2 1 -1 1 -1 1 -1 1 -1 1 -1 3 1 2 3 -1 -2 -3 4 5 6 -1 3 2 -4 -10 -1
 

Sample Output
   
   
   
   
No Yes
 

                  
               题目大意:给你五个堆,在每一个堆里面找一个数据,如果能使得五个数相加为0输出yes否则输出no
 
               解题思路:枚举五个堆就算加一个二分查找肯定会超时,这需要用到一个分治的思想,这里枚举超时主要原因就是可能会有和相等的待会儿又会算。可以先把前两堆的和存起来,相等的只存一个。这样把1,2堆放在p1中,3,4堆放在p2中。最后直接枚举第五堆,加两个指针,一个指向最小的,一个指向最大的,然后移动。这样只会移动2*(4*10^4)次,再*2*10^2,就不会超时。(思路来源于ice_crazy)

               题目地址:Trouble

AC代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
__int64 a[4][205],p1[40005],p2[40005],b[205];
//b是第五堆,a前四堆
int t1,t2,n; //p1,p2中的脚标

//如果要把p1和p2也合并的话,需要10^10的内存,存不下,所以到这里只能枚举
void cal1()   //第1堆与第2堆合并
{
     int i,j,k=0;
     __int64 tmp[40005];
     for(i=0;i<n;i++)
       for(j=0;j<n;j++)
          tmp[k++]=a[0][i]+a[1][j];
     sort(tmp,tmp+k);
     t1=-1;   //p1中的脚标
     p1[++t1]=tmp[0];
     for(i=1;i<k;i++)
     {
          if(tmp[i]!=p1[t1])
               p1[++t1]=tmp[i];
     }
     //t1++;
}

void cal2()   //第3堆与第4堆合并
{
     int i,j,k=0;
     __int64 tmp[40005];
     for(i=0;i<n;i++)
       for(j=0;j<n;j++)
          tmp[k++]=a[2][i]+a[3][j];
     sort(tmp,tmp+k);
     t2=-1;   //p2中的脚标
     p2[++t2]=tmp[0];
     for(i=1;i<k;i++)
     {
          if(tmp[i]!=p2[t2])
               p2[++t2]=tmp[i];
     }
     //t2++;
}

int main()
{
     int T,i,j;
     scanf("%d",&T);
     while(T--)
     {
         scanf("%d",&n);  //每一堆有n个数据
         for(i=0;i<4;i++)
           for(j=0;j<n;j++)
              scanf("%I64d",&a[i][j]);
         for(i=0;i<n;i++)
           scanf("%I64d",&b[i]);
         cal1();
         cal2();
         int flag=0;
         for(i=0;i<n;i++)  //枚举第五堆
         {
              int s1=0,s2=t2; //s1,s2代表枚举时p1,p2的指针
              while(s1<=t1&&t2>=0)
              {
                   if(p1[s1]+p2[s2]+b[i]==0)
                   {
                        flag=1;
                        break;
                   }
                   if(p1[s1]+p2[s2]+b[i]<0) s1++;
                    else s2--;
              }
              if(flag) break;
         }

         if(flag) puts("Yes");
         else puts("No");
     }
     return 0;
}


你可能感兴趣的:(分治,HDU,多校联赛,合并堆)