码迷,mamicode.com
首页 > 其他好文 > 详细

常州模拟赛d8t1 友好数对

时间:2017-09-30 22:55:31      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:namespace   lld   images   技术分享   str   amp   ==   pac   证明   

技术分享

分析:其实就是问你有多少对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 友好数对

标签:namespace   lld   images   技术分享   str   amp   ==   pac   证明   

原文地址:http://www.cnblogs.com/zbtrs/p/7616284.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!