zoukankan      html  css  js  c++  java
  • 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
    " , ans) ;
    	return 0 ;
    }
    
  • 相关阅读:
    shell入门-sed-2替换功能
    shell入门-sed-1
    shell入门-grep-3-egrep
    shell入门-grep2
    shell入门-grep过滤-1
    shell入门-连接符(并且、和、或者)
    shell入门-tr替换字符和split切割大文件
    shell入门-uniq去重复和tee重定向
    class类的相关操作 --| 公有普通方法 | 私有普通方法 | 无参方法 | 有参方法
    类的封装性-- | 成员属性 | 成员方法 | 私有属性 | 私有方法 之间调用
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/10952039.html
Copyright © 2011-2022 走看看