試題描述ios |
給定4個n(1<=n<=4000)元素集合A,B,C,D,要求分別從中選取一個元素a,b,c,d,使得a+b+c+d=0。問:有多少種選法?ide 例如,A={-45,-41,-36,26,-32,100000},B={22,-27,53,30,-38,-54},C={42,56,-37,-75,-10,-6},D={-16,30,77,-46,62,45},則有5種選法:(-45,-27,42,30),(26,30,-10,-46),(-32,22,56,-46),(-32,30,-75,77),(-32,-54,56,30)。測試 |
輸入優化 |
第一行包括一個整數 T,表示測試數據組數 |
輸出3d |
對於每組數據,一個整數表示一共有多少種選法,以空行結束一組數據code |
輸入示例blog |
1 |
輸出示例內存 |
5 |
其餘說明 |
試題來源:UVA1152 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
講解:
由於n<=4000,因此得從四重循環得優化,咱們只須要將a,b,c,d排序去重,將a,b中全部組合存下來放入c,d的全部組合中二分查找。
代碼實現:
#include<iostream> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int xx=2010; int a[xx],b[xx],c[xx],d[xx],sum1[xx*xx],sum2[xx*xx],n,dex1,dex2,ans; bool ff(int l,int r,int s)//二分查找(略) { int i,j,mid; while(l<r) { mid=(l+r)/2; if(sum2[mid]==s) return true; else if(sum2[mid]>s) r=mid; else l=mid+1; } return false; } int main() { int i,j,t; scanf("%d",&t); while(t!=0) { ans=0; dex1=0; dex2=0; t--; scanf("%d",&n); for(i=0;i<n;i++) scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]); sort(a,a+n); //排序,便於去重 sort(b,b+n); sort(c,c+n); sort(d,d+n); for(i=0;i<n;i++) { if(i!=0 && a[i]==a[i-1]) continue; //去重 for(j=0;j<n;j++) { if(j!=0 && b[j]==b[j-1]) continue;//去重 sum1[dex1++]=a[i]+b[j];//將a+b的值存進sum裏 } } sort(sum1,sum1+dex1);//sum排序 for(i=0;i<n;i++) { if(i!=0 && c[i]==c[i-1]) continue;//去重 for(j=0;j<n;j++) { if(j!=0 && d[j]==d[j-1]) continue;//去重 sum2[dex2++]=c[i]+d[j]; } } sort(sum2,sum2+dex2); for(i=0;i<dex1;i++) if(ff(0,dex2,-sum1[i])) ans++;//把 -c[i]-d[j]的值在sum裏二分查找 cout<<ans<<endl; } return 0; }
若是內存超限(mle)咱們能夠犧牲時間:
#include<iostream> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int xx=4010; int a[xx],b[xx],c[xx],d[xx],sum[xx*xx],n,dex,ans; bool ff(int l,int r,int s)//二分查找(略) { int i,j,mid; while(l<r) { mid=(l+r)/2; if(sum[mid]==s) return true; else if(sum[mid]>s) r=mid; else l=mid+1; } return false; } int main() { int i,j,t; scanf("%d",&t); while(t!=0) { ans=0; dex=0; t--; scanf("%d",&n); for(i=0;i<n;i++) scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]); sort(a,a+n); //排序,便於去重 sort(b,b+n); sort(c,c+n); sort(d,d+n); for(i=0;i<n;i++) { if(i!=0 && a[i]==a[i-1]) continue; //去重 for(j=0;j<n;j++) { if(j!=0 && b[j]==b[j-1]) continue;//去重 sum[dex++]=a[i]+b[j];//將a+b的值存進sum裏 } } sort(sum,sum+dex);//sum排序 for(i=0;i<n;i++) { if(i!=0 && c[i]==c[i-1]) continue;//去重 for(j=0;j<n;j++) { if(j!=0 && d[j]==d[j-1]) continue;//去重 if(ff(0,dex,-c[i]-d[j])) ans++;//把 -c[i]-d[j]的值在sum裏二分查找 } } printf("%d\n",ans); } return 0; }