zoukankan      html  css  js  c++  java
  • HDU 6022---MG loves set(K-D树)

    题目链接

    Problem Description
    MG 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 many nonempty subset is “A Harmony Set”.
    MG thought it very easy and he had himself disdained to take the job. As a bystander, could you please help settle the problem and calculate the answer?
     
    Input
    The 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).
    Output
    As for each case, you need to output a single line.
    There should be one integer in the line which represents the number of “Harmony Set”. 
    Sample Input
    3
    4
    1 2 3 4
    5
    1 -1 2 3 -3
    6
    0 2 4 -4 -5 8
     
    Sample Output
    15
    12
    25
     
    题意:

    思路:

    看到题目数据的范围n<=30 ,枚举考虑每一个子集肯定会超时,所以这个办法不行了。怎么样降低复杂度呢?

    先化简一下,设子集为{x,y,z}满足题目要求,则x*x+y*y+z*z<=(x+y+z)*(x+y+z) 即xy+yz+xz>=0  ,所以本题就是求一个集合有多少非空子集满足集合中元素两两乘积的和大于等于0; 

    巧妙地思想:把集合分成前后两半,设前一半集合的任意一个子集的和为Xi 两两之间乘积的和为Yi ,后一半集合的任意一个子集的和为Xj 两两之间乘积的和为Yj 可以发现(a+b)*(c+d)+ab+cd>=0是子集{a,b,c,d}满足题意的要求,那么Xi*Xj+Yi+Yj>=0就是判断当前由这两个子集合起来得到的子集是否满足题意的要求。最后用K-D树优化即可。

    官方题解如下: 

    代码如下:

    #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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    TensorFlow进阶(三)---变量的创建、初始化
    TensorFlow进阶(二)---张量的操作
    TensorFlow进阶(一)----张量的阶和数据类型
    TensorFlow入门
    卷积神经网络识别手写数字实例
    解决在win系统下使用DOS命令开启TensorBoard的问题及方法步骤
    TensorFlow------单层(全连接层)实现手写数字识别训练及测试实例
    TensorFlow------TFRecords的读取实例
    TensorFlow------TFRecords的分析与存储实例
    TensorFlow------读取二进制文件实例
  • 原文地址:https://www.cnblogs.com/chen9510/p/6686685.html
Copyright © 2011-2022 走看看