HDU 6022---MG loves set (K-D tree), hduk-d
Question Link
Problem DescriptionMG is an intelligent boy. One day he was challenged by the famous master called Douer:
If the sum of the square of every element in a set is less than or equal to the square of the sum of all the elements, then we regard this set as "A Harmony Set ".
Now we give a set with n different elements, ask you how to specify nonempty subset is "A Harmony Set ".
MG thought it very easy and he had himself disdained to take the job. As a bystander, cocould you please help settle the problem and calculate the answer?
InputThe first line is an integer T which indicates the case number. (1 <= T <= 10)
And as for each case, there are 1 integer n in the first line which indicate the size of the set (n <= 30 ).
Then there are n integers V in the next line, the x-th integer means the x-th element of the set (0 <=| V |<= 100000000 ).
OutputAs for each case, you need to output a single line.
There shoshould be one integer in the line which represents the number of "Harmony Set ".
Sample Input341 451-1 2 3-360 2 4-4-5 8
Sample Output151225 question:
Ideas:
When we see that the range of the question data is n <= 30, enumeration considers that each subset will definitely time out, so this method cannot work. How can we reduce complexity?
First, reduce the subset to {x, y, z} to meet the requirements of the question. Then, x * x + y * y + z * z <= (x + y + z) * (x + y + z) That is xy + yz + xz> = 0, therefore, this question is to find the number of non-null subsets in a set that satisfy the sum of the elements in the set with the product of two elements greater than or equal to 0;
Clever thought: divide a set into two halves, and set the sum of any subset of the first half of the Set and the sum of the products of the Xi pairs to Yi, the sum of any subset of the last half of the Set and the product between Xj and Yj can be found (a + B) * (c + d) + AB + cd> = 0 indicates that the subset {a, B, c, d} meets the requirements of the question, then, Xi * Xj + Yi + Yj> = 0 is used to determine whether the subset obtained from the two child sets meets the requirements of the question. Finally, use the K-D tree optimization.
The official question is as follows:
The Code is as follows:
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;typedef long long LL;const int N=1000005;LL a[40];int flag[4*N];int idx;struct Node{ LL f[2]; LL mx[2]; LL mn[2]; int size; bool operator<(const Node& s)const { return f[idx]<s.f[idx]; }}A[N],B[N],tr[4*N];void update(int i){ int s=1; if(flag[i<<1]) { for(int k=0;k<=1;k++) { if(tr[i<<1].mn[k]<tr[i].mn[k]) tr[i].mn[k]=tr[i<<1].mn[k]; if(tr[i<<1].mx[k]>tr[i].mx[k]) tr[i].mx[k]=tr[i<<1].mx[k]; } s+=tr[i<<1].size; } if(flag[i<<1|1]) { for(int k=0;k<=1;k++) { if(tr[i<<1|1].mn[k]<tr[i].mn[k]) tr[i].mn[k]=tr[i<<1|1].mn[k]; if(tr[i<<1|1].mx[k]>tr[i].mx[k]) tr[i].mx[k]=tr[i<<1|1].mx[k]; } s+=tr[i<<1|1].size; } tr[i].size=s;}void build(int l,int r,int i,int deep) { if(l>r) return; int mid=(l+r)>>1; idx=deep; flag[i]=1; flag[i<<1]=0; flag[i<<1|1]=0; nth_element(B+l,B+mid,B+r+1); for(int k=0;k<=1;k++) tr[i].mx[k]=tr[i].mn[k]=tr[i].f[k]=B[mid].f[k]; build(l,mid-1,i<<1,1-deep); build(mid+1,r,i<<1|1,1-deep); update(i);}int check(LL x1,LL y1,LL x2,LL y2){ if(x1*x2+y1+y2>=0) return 1; return 0;}int count(Node p,int i){ int re=0; re+=check(tr[i].mn[0],tr[i].mn[1],p.f[0],p.f[1]); re+=check(tr[i].mn[0],tr[i].mx[1],p.f[0],p.f[1]); re+=check(tr[i].mx[0],tr[i].mn[1],p.f[0],p.f[1]); re+=check(tr[i].mx[0],tr[i].mx[1],p.f[0],p.f[1]); return re;}int query(Node p,int i){ if(!flag[i]) return 0; if(count(p,i)==4) return tr[i].size; int re=check(p.f[0],p.f[1],tr[i].f[0],tr[i].f[1]); if(count(p,i<<1)) re+=query(p,i<<1); if(count(p,i<<1|1)) re+=query(p,i<<1|1); return re;}int main(){ int T; cin>>T; while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); int mid=n/2; int tt=(1<<mid); int tot1=0,tot2=0; for(int i=0;i<=tt-1;i++) { A[tot1].f[0]=0; A[tot1].f[1]=0; for(int k=1;(1<<(k-1))<tt;k++) { if((1<<(k-1))&i) { A[tot1].f[1]+=A[tot1].f[0]*a[k]; A[tot1].f[0]+=a[k]; } } tot1++; } int tt2=1<<n; for(int i=0;i<tt2;i+=tt) { B[tot2].f[0]=0; B[tot2].f[1]=0; for(int k=mid+1;(1<<(k-1))<tt2;k++) { if((1<<(k-1))&i) { B[tot2].f[1]+=B[tot2].f[0]*a[k]; B[tot2].f[0]+=a[k]; } } tot2++; } /*for(int i=0;i<tot1;i++) cout<<A[i].f[0]<<" "<<A[i].f[1]<<endl; cout<<"-----------------"<<endl; for(int i=0;i<tot2;i++) cout<<B[i].f[0]<<" "<<B[i].f[1]<<endl;*/ build(0,tot2-1,1,0); int ans=-1; for(int i=0;i<tot1;i++) { ans+=query(A[i],1); } printf("%d\n",ans); } return 0;}