F:异或序列
题目描述
Venn有一个数列a1,a2,...,an。有一天,BLUESKY007拿来了一个正整数X。Venn是一个特别喜欢异或(xor)运算的孩子,她也很喜欢BLUESKY007。于是,Venn就想知道,自己能找到多少对数(i,j)能够满足aixoraj=X。两个数对(i1,j1)与(i2,j2)不同,当且仅当i1≠i2或者j1≠j2。
输入
第一行两个正整数n,X,分别表示数列的长度以及Bluesky带来的整数。
第二行包含n个正整数,表示数列{an}。输出
一行一个整数表示答案。
样例输入 Copy
5 1 1 4 2 2 5样例输出 Copy
2提示
样例解释:这两对是(2,5)与(5,2)。
【数据范围】
对于50%的数据,1≤n≤2000。
对于接下来20%的数据,1≤ai≤100000。
对于100%的数据,1≤n≤1000000,1≤ai≤230,1≤X≤230。
我一拿到异或就很开心,因为异或的我已经做了好几道求和的了。
这题我的思路是map,然后查找,超时。
然后我还以为是什么高级算法,就放弃了。
赛后补题花絮:问了大佬以后是二分查找
我用stl(我只会stl!)超时,氧气优化也不行,快读c语言试了个遍,卡在(1000+)s
后来上网查了一下,stl慢,手打upper和lower
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
typedef long long ll;
typedef double db;
const int maxn=1e5+5;
ll n,x;
ll a[1000005];
ll cnt;
inline ll read()
{
ll 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*10+ch-48;
ch=getchar();
}
return x*f;
}
void write(ll x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)write(x / 10);
putchar(x % 10 + '0');
}
int lowbou(ll a[],ll l,ll r,ll tar)
{
while(l<=r){
ll mid=(l+r)/2;
if (a[mid]<tar) l=mid+1;
else r=mid-1;
}
return l;
}
int uppbou(ll a[],ll l,ll r,ll tar)
{
while(l<=r){
ll mid=(l+r)/2;
if (a[mid]<=tar) l=mid+1;
else r=mid-1;
}
return l;
}
int main ()
{
n=read();
x=read();
for(ll i=1; i<=n; i++)
{
a[i]=read();
}
sort(a+1,a+1+n);
for(ll i=1; i<=n; i++)
{
ll sb=a[i]^x;
cnt+=uppbou(a,1,n,sb)-lowbou(a,1,n,sb);
}
write(cnt);
return 0;
}