牛客练习赛77-小结

A,B签到,C整数分块简单变形
D.优化枚举+手写hash
题目大意:

给你两个集合。问你两个集合中有多少个数对,它们二进制中恰好有两位不同.
n ≤ 1 e 5 , a i < 2 30 n \leq 1e5,a_i< 2^{30} n1e5,ai<230

题目思路:

将一个集合丢入hash,枚举另一个集合,暴力枚举两个不同的位,然后查询。复杂度: O ( 30 ∗ 30 ∗ n ) O(30*30*n) O(3030n).

考虑优化。这么思考这个问题,我们先修改第一个集合里数的一个二进制位,然后对第二个集合,我们同样也修改一个二进制位,然后查询相等的对数。所以做法就是:对第一个集合每个数枚举修改一个不同的位,丢入hash.然后对第二个集合枚举另一个不同的位。查询即可。 还要注意 可能修改的是同一位,所以得容斥掉值同时存在于两个集合的情况。然后修改的方案也是有两种。所以最终答案要除2.如下图:在这里插入图片描述

复杂度: O ( 30 ∗ n ) O(30*n) O(30n)

但是这题卡unordered_map(具体原理见Neal大佬的cf博客),所以得手写hash。模板如下:

模板一:

模数: 1000011 ( 非 质 数 ) 1000011(非质数) 1000011(),运行时间: 740 m s 740ms 740ms
模数: 2000003 ( 质 数 ) 2000003(质数) 2000003(),运行时间: 400 m s 400ms 400ms
模数: 9000011 ( 质 数 ) 9000011(质数) 9000011(),运行时间: 290 m s 290ms 290ms
理论上模数越大,且是质数,时间复杂度就比较低

定址方法:除留余数法
解决冲突的方法:拉链法(链式向前星)

struct HashSet {
    static const int N = 9e6 + 11;
    struct node {
        int k, v, nex;
    } buf[N];
    int h[N], tot, mod = N;
    void add(int x) {
        int pos = x % mod;
        for (int i = h[pos]; i; i = buf[i].nex) {
            if (buf[i].k == x) { buf[i].v++; return; }
        }
        buf[++tot] = { x, 1, h[pos] };
        h[pos] = tot;
    }
    int ask(int x) {
        int pos = x % mod;
        for (int i = h[pos]; i; i = buf[i].nex) {
            if (buf[i].k == x) return buf[i].v;
        }
        return 0;
    }
}s;
E.待补.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值