【题解】2021.9.11 - zhengru IOI 七连测 Day3
\(\color{Red}{How-great-the-day-is-!(Wrong)}\)
T1 斯诺克
思路
代码
T2 翻转
思路
代码
T3 数对
思路
-
对于每一个 \(a_i\) 和 \(b_j\) ,当且仅当 \(a_i \oplus 2^x=b_j \oplus 2^y\) 且 \(x ≠ y\) 。
-
于是,只需要对于每一个 \(a_i\) 算出 \(a_i \oplus 2^x\) 的值,然后找与其相等的 \(b_j\) 的值即可。
-
需要注意的是,当 \(a_i=b_j\) 时,对于每个次幂都会统计一次答案,减去即可。
-
另外,因为判断的只是相等,所以对于每个数对有两种异或方式,答案要除以二。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
int na[100233],nb[100233],cna,cnb,n,m;
map<int,int> sam;
long long ans,pa[3000233],pb[3000233];
int main(){
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;++i){
scanf("%d",&na[i]);
sam[na[i]]++;
for(register int j=0;j<30;++j){
pa[++cna]=na[i]^(1<<j);
}
}
for(register int i=1;i<=m;++i){
scanf("%d",&nb[i]);
ans-=sam[nb[i]]*30;
for(register int j=0;j<30;++j){
pb[++cnb]=nb[i]^(1<<j);
}
}
sort(pa+1,pa+cna+1);sort(pb+1,pb+cnb+1);
for(register int i=1,l=1,r=1;i<=cna;++i){
while(pb[l]<pa[i]&&l<=cnb) ++l;
while(pb[r]<=pa[i]&&r<=cnb) ++r;
if(pa[i]==pb[l]) ans+=(r-l);
}
printf("%lld\n",ans>>1);
return 0;
}