牛客练习赛77D

传送门

这个题看完后,很显然我们要通过枚举各个位上得数将复杂度降为log级的,因此就诞生了我的第一发交的

rep(i,1,n){
        rep(j,0,29){
            rep(l,j+1,29){
                a[i]^=(1<<j);
                a[i]^=(1<<l);
                ans+=(upper_bound(b+1,b+1+m,a[i])-b)-(lower_bound(b+1,b+1+m,a[i])-b);
                a[i]^=(1<<j);
                a[i]^=(1<<l);
            }
        }
    }

枚举两个异或相异的地方,然而没有侥幸,直接t了。

那么枚举两个地方是不行的,那麽枚举一个应该可以吧,对数组a中每一个数的每一位的异或后的数存起来,对数组b中每一个数的每一位异或后在存的数里面得到个数累加。
但在这其中会有重复计算和错误计算,如当a中每个元素和b的每个元素相同时,这个数每一位的异或值都会被重复计算,因此,最后ans要减去b中出现在a中的元素乘以位数。
然后对于一组(x,y),由于x,y的二进制只有两位不一样,因此这种方法会导致答案是加倍,因此最后要除二。

map<int,int>s,z;
n=read(),m=read();
    rep(i,1,n){
        tmp=read();
        rep(j,0,29){
            s[tmp^(1<<j)]++;
        }
        z[tmp]++;
    }
    ll ans=0;
    rep(i,1,m){
        tmp=read();
        rep(j,0,29) {
            ans+=s[tmp^(1<<j)];
        }
        ans-=30*z[tmp];
    }
    print(ans>>1);

然后仍是光荣tle,map实在是太慢了,我看到大佬都是手写哈希表,嗯,手写哈希还是快,然后就A了。


class Hash{
private: 
    int last[maxn],nxt[maxn],cnt=0;
    int a[maxn],b[maxn];
public:
    void insert(int x){
        int t=x%N;
        for(int i=last[t];i;i=nxt[i]){
            if(x==a[i]){
                b[i]++;
                return;
            }
        }
        a[++cnt]=x;b[cnt]=1;
        nxt[cnt]=last[t];
        last[t]=cnt;
    }
    int query(int x){
        int t=x%N;
        for(int i=last[t];i;i=nxt[i]){
            if(a[i]==x) return b[i];
        }
        return 0;
    }
}s,z;

int main(){  
#ifndef ONLINE_JUDGE
    freopen("in0.txt","r",stdin);
   // freopen("2.out","w",stdout);
#endif 
    int tmp;
    n=read(),m=read();
    rep(i,1,n){
        tmp=read();
        s.insert(tmp);
        rep(j,0,29){
            z.insert(tmp^(1<<j));
        }
        
    }
    ll ans=0;
    rep(i,1,m){
        tmp=read();
        rep(j,0,29) {
            ans+=z.query(tmp^(1<<j));
        }
        ans-=s.query(tmp)*30;
    }
    print(ans>>1);
    return 0;
}
posted @ 2021-02-27 00:27  Mr_cold  阅读(35)  评论(0编辑  收藏  举报