题目描述

给定一个长度为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 \le 10^3 $

对于 50% 数据 $ n \le 5 \times 10^4 , 0 \le a_i \le 10^9 $

对于 100% 数据 $ n \le 10^6 , 0 \le a_i \le 10^9 $

这个题之前想枚举二的整次幂,然后二分查找判断来着....

于是代码长这样:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define lowbit(x) ( - x & x )
#define ll long long const int N = 1e6 + 5 ; int n,v[N];
ll ans;
ll mi[N]; inline int read(){
int x = 0 , f = 1 ;char ch = getchar () ;
while(ch < '0' || ch > '9'){if(ch == '-') f = - 1 ;ch = getchar () ;}
while( ch >= '0' && ch <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( ch ^ 48 ) ;ch = getchar () ;}
return f * x ;
} inline bool check ( int l , int r , int val ){
#define mid ( ( l + r ) >> 1 )
while( l <= r ){
if( v[mid] == val ) return true ;
if( v[mid] > val ) r = mid - 1 ;
if( v[mid] < val ) l = mid + 1 ;
}
#undef mid
return false ;
} int main(){
n = read () ;mi[0] = 1 ;
for(int i = 1 ; i <= 33 ; ++ i ) mi[i] = ( mi[i - 1] << 1 ) ;
for(int i = 1 ; i <= n ; ++ i ) v[i] = read () ;
std::sort( v + 1 , v + n + 1 );
for(int i = 1 ; i <= n ; ++ i ){
int dir = std::upper_bound( mi + 1 , mi + 33 + 1 , v[i] ) - mi ;
int tmp = mi[dir] - v[i];
if( check( i , n , tmp ) ) ++ ans ;
}
printf("%lld\n" , ans );
return 0;
}

显然这个做法会T到飞起!

那么我就想怎么消 $ log $ 然后旁边的 $ wqy \ 大\ 佬\ && zs \ 大\ 佬\ $ 告诉我可以用双指针来优化,做到消除 $ log $

然后我冥思苦想,终于和 \(DYJ\) 在一番激烈争论后确定了这题的双指针怎么搞,于是就AC了

具体思路也不怎么难,大体就是先排一遍序,然后枚举二的整次幂,双指针扫区间,统计答案

扫区间的时候,不断地根据单调性移动指针就好了

要特判一坨一样的值,因为扫到一坨一样的值是可以直接 \(\Theta(1)\) 算出来的,完全不必要去扫

于是,代码长这样:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cctype>
#define Noip2018RPINF return 0
#define Ll long long const int N = 1e6 + 3;
LL a[N];
int n,p[33]; inline int read(){
int v = 0,c = 1;char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-') c = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
v = ( v << 3 ) + ( v << 1 ) + ( ch ^ 48 );
ch = getchar();
}
return v * c;
}
int main(){
n = read();
p[0] = 1;
long long ans = 0;
for(int i = 1;i <= 30;++i) p[i] = p[i - 1] << 1;
for(int i = 1;i <= n;++i) a[i] = read();
std::sort(a + 1,a + n + 1) ;
for(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);
Noip2018RPINF;
}

最新文章

  1. SQL Server 远程连接出错~~~无法访问服务器
  2. shell-script的简单举例
  3. 阿里im即时通讯 h5 demo
  4. MINA2 框架详解(转)
  5. ARM指令分类及其寻址方式
  6. angular中的表单验证
  7. Android学习笔记之使用百度地图实现Poi搜索
  8. 清除Eclipse和Myeclipse中的工作空间目录
  9. 解决vim不能使用方向键和退格键问题
  10. 深入浅出了解OCR识别票据原理
  11. Oracle DataGuard 11g 双机实验
  12. struts拦截器的知识
  13. vue 的动画
  14. Vue.js示例:GitHub提交(watch数据,created钩子,filters过滤); 网格组件(功能:1.检索,2排序);
  15. c#: 以模态窗口显示于其它进程窗体之前
  16. BeyondCompare
  17. (KMP)Simpsons’ Hidden Talents -- hdu -- 2594
  18. strcpy,memcpy,memset函数实现
  19. .Net高级技术——结构体
  20. Asp.Net MVC:return View()、return View(&quot;Login&quot;)、return Login()、return RedirectToAction(&quot;Login&quot;) 的区别

热门文章

  1. Java泛型中&lt;? extends E&gt;和&lt;? super E&gt;的区别
  2. PS制作漂亮紫色霓虹灯光文字
  3. 使用Nodejs在Windows上调用CMD命令
  4. Java的selenium代码随笔(4)
  5. Shiro限制登录尝试次数
  6. c语言第三次课
  7. kubernetes 报错汇总
  8. 初步了解Bootstrap4
  9. 机器学习---线性回归(Machine Learning Linear Regression)
  10. css常用单位