常州模拟赛d8t1 友好数对

Posted zbtrs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常州模拟赛d8t1 友好数对相关的知识,希望对你有一定的参考价值。

分析:其实就是问你有多少对a,b有且仅有两位不相同.我们可以先枚举这两位,对应ai枚举一位,对应bi枚举一位,如果ai^(1<<x) == bi^(1<<y),证明恰好有两位不一样,那么ans++.

      考虑怎么快速地得出答案,我们可以用一个数组记录ai^(1<<x)出现了多少次,但是因为ai,bi可能有2^30存不下,所以要用到hash表。数据中给定的ai,bi可能有相等的,这个在后面的计算中每一位都会被重复计算一次,为了方便起见,我们规定所有数的位数都是30位,不够就补0,所以查询到有多少个ai与bi相等,就减30*个数.最后在输出答案的时候要除以2,因为如果a的第三位和b的第五位异或1后ab相同,a的第五位和b的第三位异或1后ab相同,那么(a,b)数对就会被计算两次,实际上应该只被计算一次.所以要除以2。

      不要忘了在第一次用完链表后清空链表.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int mod = 10000019;

int head[mod], to[mod], nextt[mod], tot, n, m, a[100010], b[100010],num[mod];
long long ans;

void add(int x)
{
    int t = x % mod;
    for (int i = head[t]; i; i = nextt[i])
    {
        if (to[i] == x)
        {
            num[i]++;
            return;
        }
    }
    to[++tot] = x;
    num[tot] = 1;
    nextt[tot] = head[t];
    head[t] = tot;
}

int query(int x)
{
    int t = x % mod;
    for (int i = head[t]; i; i = nextt[i])
        if (to[i] == x)
            return num[i];
    return 0;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        add(a[i]);
    }
    for (int i = 1; i <= m; i++)
    {
        scanf("%d", &b[i]);
        ans -= 30 * query(b[i]);
    }
    tot = 0;
    for (int i = 1; i <= n; i++)
        head[a[i] % mod] = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 0; j < 30; j++)
            add(a[i] ^ (1 << j));
    for (int i = 1; i <= m; i++)
        for (int j = 0; j < 30; j++)
            ans += query(b[i] ^ (1 << j));
    printf("%lld\\n", ans / 2);

    return 0;
}

 

以上是关于常州模拟赛d8t1 友好数对的主要内容,如果未能解决你的问题,请参考以下文章

ZZNUOJ_C语言1105:判断友好数对(函数专题)(完整代码)

友好数对

zzuli oj 1105 友好数对

[coci2011]友好数对 容斥

COCI2011:友好数对

1105 判断友好数对