zoukankan      html  css  js  c++  java
  • 发财兔1A

    题目描述

    给定一个长度为n的正整数序列a[i],计算出有多少个i<j的数对,a[i]+a[j]为二的次幂,也就是说存在一个正整数x满足a[i]+a[j]==2^x。

    输入

    第一行一个整数n。
    第二行n个整数,其中第i个整数为a[i]。 
     

    输出

    一行一个整数表示数对的数量。

    样例输入

    4
    7 3 2 1
    

    样例输出

    2
    

    提示

    对于 20% 数据 n<=1000。
    对于 50% 数据  n<=50000,0<=a[i]<=10^9。
    对于 100% 数据  n<=1000000,0<=a[i]<=10^9。

    思路:这里我是用字典树做的;

    因为我们把一个数变成二进制后;

    我们找的相对应的符合条件的字符串是确定的,例如如果我们找和3对应的符合要求的数时候;

    我们可以知道3的二进制是11;

    因此相对应的所要找的是1,101,1011,10111等;

    如果二进制是9,二进制是1001;那么我们需要找的是111,11101,111011,1110111等

    我们可以得到结论,满足条件的最小的值肯定是和需要找的串(长度为K)相加为2^K;

    即与1000101满足条件的最小的值和他想加为00000001;

    次大的数相加肯定为000000001,然后是000000001........;

    因此我们对于一个值,我们只要找出这些满足条件的串就可以;

    需要注意的是a[i]可能等于0,因此这种情况要单独处理;

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+5;
    typedef long long ll;
    int tree[5*maxn][3];
    int sum[5*maxn];
    int tot;
    void insert_(int *str,int len)
    {
       int root=0;
       for(int i=0;i<len;i++)
       {
           int id=str[i];
           if(!tree[root][id]) tree[root][id]=++tot;
           if(i==len-1)
           {
                sum[tree[root][id]]++;//记录节点访问次数
           }
           root=tree[root][id];
       }
       //root在此对应某个单词,一一对应
    }
    int find_(int *str,int len)
    {
        int root=0;
        for(int i=0;i<len;i++)
        {
            int id=str[i];
           if(!tree[root][id]) return 0;
            root=tree[root][id];
        }
        return sum[root];//返回当前字符串结尾节点的访问次数,也就是作为前缀的出现次数
    }
    int main()
    {
        tot=0;
        int n,m;
        cin>>n;
        ll ans=0;
        int ans0=0;
        int ans2=0;
        for(int i=0;i<n;i++)
        {
            int ss;
            int a[33];
            int b[33];
            scanf("%d",&ss);
            int k=0;
            if(ss==0)//记录零的个数,0不需要插入,只需要找到有多少个2^X就可以
            {
                ans+=ans2;
                ans0++;
                continue;
            }
            int temp=0;
            while(ss>0)
            {
                a[k++]=ss%2;
                if(ss%2==1)
                {
                    temp++;
                }
                ss/=2;
            }
            if(temp==1&&k!=1)//记录多少个2^k,不能是1,k>0;
            {
                ans+=ans0;
                ans2++;
            }
            int po;
            for(int i=0;i<k;i++)
            {
               if(a[i]==1)
               {
                   b[i]=1;
                   po=i;
                   break;
               }
               else
               {
                   b[i]=0;
               }
            }
            for(int j=po+1;j<k;j++)
            {
                if(a[j]==0)
                {
                    b[j]=1;
                }
                else
                {
                    b[j]=0;
                }
            }
            int tempp;
            for(int jj=k-1;jj>=0;jj--)
            {
                if(b[jj]==1)
                {
                    tempp=jj;
                    break;
                }
            }
            ans+=find_(b,tempp+1);
            for(int ii=k;ii<32;ii++)
            {
                b[ii]=1;
                ans+=find_(b,ii+1);
            }
            insert_(a,k);
        }
        printf("%lld
    ",ans);
        return 0;
    }
     
  • 相关阅读:
    不同等级数据源的多级缓冲环的生成
    从DataTable到List<Model>(C#.net)
    string与char之间的转换以及如何获得string所占位数
    AndroidKotlin
    Android高级POS开发
    IOS 应用开发
    Android切屏的处理
    Android POS开发
    Android深入理解JNI
    Android的IPC机制Binder
  • 原文地址:https://www.cnblogs.com/xiaolaji/p/10263631.html
Copyright © 2011-2022 走看看