BZOJ 4264 小c找朋友 - hash

传送门

题目大意:

给定一张无向图,求满足以下条件的点对 (x,y) 数目:对任意点 z (z!=x,y),边 (x,z) 和 (y,z) 同时存在或同时不存在。

题目分析:

首先要分析的出如果xy满足要求,那么x和y的连边点集应该是相同的,这里又分为两种情况:

  • xy之间有边,加上自己的hash值后求集合哈希值出现的次数
  • xy之间没有边,直接hash求不包含自己的集合哈希值出现的次数

bzoj加上srand(time(0))就会RE,有毒

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<cmath>
#include<ctime>
using namespace std;
typedef long long ll;
namespace IO{
    inline int read(){
        int i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
    inline void wr(ll x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}using namespace IO;

const int N = 1e6 + 5, M = 1e6 + 5;
int n, m;
typedef unsigned long long ull;

const int Mod = 233333;
ull val[N], sum[N];
ll ans, degree[N];
typedef pair<ull, ll> P;
typedef pair<int, int> EP;
vector<EP> edges;
vector<P> hashMap[Mod + 5];

inline void insert(ull x, ll c){
    int key = x % Mod;
    for(int i = 0; i < hashMap[key].size(); i++)
        if(hashMap[key][i].first == x) {hashMap[key][i].second+=c;return;}
    hashMap[key].push_back(P(x, c));
}

inline ll query(ull x){
    int key = x % Mod;
    for(int i = 0; i < hashMap[key].size(); i++)
        if(hashMap[key][i].first == x) return hashMap[key][i].second;
    return 0;
}

int main(){
    n = read(), m = read();
    for(int i = 1; i <= n; i++) val[i] = 1ull * rand() * rand() + rand() ;
    for(int i = 1; i <= m; i++){
        int x = read(), y = read(); edges.push_back(EP(x, y)); degree[x]++, degree[y]++;
        sum[x] += val[y], sum[y] += val[x];
    }
    
    for(int i = 1; i <= n; i++) insert(sum[i],1);
    for(int i = 1; i <= n; i++){
        ll x = query(sum[i]);  insert(sum[i], -x);
        ans += x * (x - 1) / 2;
    }
    for(int i = 0; i < edges.size(); i++){
        int x = edges[i].first, y = edges[i].second;
        if(degree[x] == degree[y] && sum[x] + val[x] == sum[y] + val[y]) ans++;
    }
    wr(ans), putchar('\n');
    return 0;    
} 
posted @ 2017-10-16 23:15  CzYoL  阅读(256)  评论(0编辑  收藏  举报