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 ;
}
顺风不浪,逆风不怂。