2次幂的个数

题目描述

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

输入

输入文件A.in。

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

输出

输出文件A.out。

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

样例输入

4
7 3 2 1

样例输出

2

【样例输入2】

3
1 1 1

【样例输出2】

3

【数据范围】

对于 20% 数据 $ n≤10^3 $
对于 50% 数据 $ n≤5×10^4,0≤ai≤10 ^9 $
对于 100% 数据 $ n≤10 ^6 ,0≤ai≤10 ^9 $

solution :

$ p[i] $ : 预先处理出 $ 2^i $ ,因为数据范围小于 $ 10 ^9 $ ,所以就处理到三十就好了。

第一次指针:找到 $ 2 ^i $ 下每种情况。
第二次指针:找到在每种情况下有多少种重复的情况,然后用乘法原理一次就处理出来。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define re register
using namespace std ;
const int maxn = 1000005 ;

inline int read () {
    int f = 1 , x = 0 ;
    char ch = getchar () ;
    while(ch > '9' || ch < '0')  {if(ch == '-') f = -1 ; ch = getchar () ;}
    while(ch >= '0' && ch <= '9')  {x = (x << 1) + (x << 3) + ch - '0' ; ch = getchar () ;}
    return x * f; 
}

int n , a[maxn] , p[maxn] ;
long long ans ;

int main () {
    n = read () ;
    p[0] = 1 ;
    for(re int i = 1 ; i <= n ; ++ i)
        a[i] = read() ;
    for(re int i = 1 ; i <= 30 ; ++ i)
        p[i] = p[i - 1] << 1 ;
    sort(a + 1 , a + 1 + n) ;
    for(re int j = 30 ; j >= 0 ; -- j) {
        int l = 1 , r = n ;
        while(l < r) {
            while(a[l] + a[r] > (long long)p[j])  -- r ;
            while(a[l] + a[r] < (long long)p[j])  ++ l ;
            if(l >= r)  break ;
            if(a[l] == a[r]) {
                if(a[l] + a[r] == (long long)p[j]) 
                    ans += (long long)(r - l + 1) * (r - l) / 2 ;
                    break ;
            }
            int ll = l , rr = r ;
            long long sum1 = 0 , sum2 = 0 ;
            if(a[ll] + a[rr] == (long long)p[j]) {
                while(a[ll] == a[l])  ++sum1 , ++ ll ;
                while(a[rr] == a[r])  ++sum2 , ++ rr ;
            }
            ans += sum1 * sum2 ;
            l = ll , r = rr ;
        }
    }
    printf("%lld\n" , ans) ;
    return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/Stephen-F/p/10952039.html