1. 程式人生 > >UVa-1152 4 Values Whose Sum Is 0

UVa-1152 4 Values Whose Sum Is 0

pen style break print 存在 次方 訓練 bits names

一道學校裏div2 的訓練題

題目大意是給出n(<=4000)行四列的數字(<=2^28),我們需要從每列中選取一個數字使得四個數字之和恰好為0,問有多少種選取方案。

所有組合是4000的4次方直接爆掉了,但是可以二分。(O(N)=N^2logN)

左邊2列(4000*4000種)中各取一個數字求和,右邊同理,排序後一個從小到大,另一個從大到小找。開始錯的地方是沒有考慮類似 "1 1 1 1"與 "-1 -1 -1 " 這種應該加 3*4 而不是++,於是就用了結構體數組將相同的和存在一起並計數。

技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define EPS 1e-9
 3
using namespace std; 4 5 typedef long long ll; 6 const int INF=0x3f3f3f3f; 7 const int MAXN=16000000+6; 8 9 long ans; 10 long Bin[2][MAXN]; 11 int cnt[2]; 12 int tot[2]; 13 int raw[4][4003]; 14 int N; 15 16 struct Node{ 17 int dat,num; 18 }BN[2][MAXN]; 19 20 void getBin(int t){ 21 for(int i=0
;i<N;++i){ 22 for(int j=0;j<N;++j){ 23 Bin[t][cnt[t]++]=raw[2*t][i]+raw[2*t+1][j]; 24 } 25 } 26 } 27 28 int main(){ 29 //freopen("data.out","w",stdout); 30 int Test; 31 scanf("%d",&Test); 32 for(int cntT=1;cntT<=Test;++cntT){ 33 ans=0;cnt[0
]=cnt[1]=0; 34 tot[0]=tot[1]=0; 35 scanf("%d",&N); 36 for(int i=0;i<N;++i){ 37 for(int j=0;j<4;++j){ 38 scanf("%d",&raw[j][i]); 39 } 40 } 41 getBin(0); 42 getBin(1); 43 sort(Bin[0],Bin[0]+cnt[0]); 44 sort(Bin[1],Bin[1]+cnt[1]); 45 46 for(int i=0;i<2;++i){ 47 BN[i][tot[i]].dat=Bin[i][0]; 48 BN[i][tot[i]++].num=1; 49 for(int j=1;j<cnt[i];++j) { 50 if(Bin[i][j]==BN[i][tot[i]-1].dat) 51 BN[i][tot[i]-1].num+=1; 52 else{ 53 BN[i][tot[i]].dat=Bin[i][j]; 54 BN[i][tot[i]++].num=1; 55 } 56 } 57 } 58 59 for(int i=0,j=tot[1]-1;i<tot[0];++i){ 60 while(BN[0][i].dat+BN[1][j].dat>0&&j>=1) j--; 61 if(BN[0][i].dat+BN[1][j].dat>0) break; 62 63 if(BN[0][i].dat+BN[1][j].dat==0) ans+=BN[0][i].num*BN[1][j].num; 64 else if(BN[0][i].dat+BN[1][j].dat<0) continue; 65 } 66 printf("%ld\n",ans); 67 if(cntT!=Test) puts(""); 68 } 69 return 0; 70 }
View Code

數據會爆而且又是求和的性質啥的就應該往二分想。

UVa-1152 4 Values Whose Sum Is 0