1. 程式人生 > >常州模擬賽d8t1 友好數對

常州模擬賽d8t1 友好數對

i++ turn 但是 出現 img src images mage 計算

技術分享

分析:其實就是問你有多少對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 友好數對