这里是缅甸北部..

写傻了的D

复杂度:

思路正确,但实现实现的有点傻了

首先考虑 后恰好有两位是1,怎么用数学语言表示:

那么有:

那么很显然,只需要保证,然后求相等即可。

这样就可以先把一边用哈希存起来(掉了),遍历另一边所有的结果。

这时候得到的结果是包含 的,考虑还满足上述式子:

相等成立的话

必然有:,所以减去相等的方案数就好了。

最后方案数就是答案

这里其实不需要容斥,看rk1代码即可,思路是类似的。

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e7+700;
const int M = 1e6+8;
const ll mod= 1e6+7;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
struct Hash{
    int e,next,w;
}edge[maxn];
int head[maxn];
ll cnt=0;
map<ll,int>ca;
void Insert(int x){
    ll temp=x%mod;
    for(int i=head[temp];~i;i=edge[i].next){
        if(edge[i].e==x){
            edge[i].w++;
            return;
        }
    }
    edge[cnt]=Hash{x,head[temp],1};
    head[temp]=cnt++;
}
ll Find(ll x){
    ll temp=x%mod;
    for(int i=head[temp];~i;i=edge[i].next){
        if(edge[i].e==x) return edge[i].w;
    }
    return 0;
}
ll a[maxn],b[maxn];
int main(){
    memset(head,-1,sizeof(head));
    read(n);read(m);
    for(int i=1;i<=n;i++){
        read(a[i]);
        ca[a[i]]++;
    }
    ll tmp = 0;
    for(int i=1;i<=m;i++){
        read(b[i]);
        tmp += ca[b[i]]*30;
    }
    for(int i=1;i<=n;i++){
        for(int k=0;k<30;k++)
            Insert(a[i]^(1ll<<k));
    }
    ll ans = 0;
    for(int i=1;i<=m;i++)
        for(int k=0;k<30;k++)
            ans += Find(b[i]^(1<<k));
    dl((ans-tmp)/2);
    return 0;
}