codeforces 154 C - Double Profiles

xiaoxiao2021-02-28  77

题目大意:

N个点,M条边,问有多少个点对对除彼此之间的点外对其他点的连接情况完全相同。(N,M<=1,000,000)

显然能想到hash。如果我们给每个点一个hash值,再将每个和这个点相连的点加上这个hash值。

不难发现,如果不考虑彼此的连接情况,我们可以进行hash。hash后会被分成若干个连接情况完全相同的块,那么这些块对答案的贡献就是size*(size-1)/2。

如果彼此之间有边相连,那么我将连接情况减去彼此的hash值,再判断是否相同。若相同,则对答案的贡献是1。

由于神奇的原因,似乎不容易被卡掉。我在这里用了自然溢出,出现重复的几率相当小(并不是没有)

#include<bits/stdc++.h> #define N 1000100 using namespace std; typedef unsigned long long ULL; typedef long long LL; const ULL H=103; inline void read(int &a){ a=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch<='9'&&ch>='0') a=a*10+ch-'0',ch=getchar(); } ULL bas=1; int n,m; int a[N],b[N]; ULL has[N],cf[N]; vector<int> v[N]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ read(a[i]);read(b[i]); v[a[i]].push_back(b[i]); v[b[i]].push_back(a[i]); } for(int i=1;i<=n;i++){ if(!v[i].size()) i++; int len=v[i].size(); for(int j=0;j<len;j++) has[v[i][j]]+=bas; cf[i]=bas; bas*=H; } long long ans=0; for(int i=1;i<=m;i++){ if(has[a[i]]-cf[b[i]]==has[b[i]]-cf[a[i]]) ans++; } sort(has+1,has+n+1); ULL la=-1; int tot=0; for(int i=1;i<=n;i++){ if(la!=has[i]){ la=has[i]; ans+=LL(tot)*LL(tot-1)/2; tot=0; } tot++; } ans+=LL(tot)*LL(tot-1)/2; printf("%I64d\n",ans); return 0; }

转载请注明原文地址: https://www.6miu.com/read-52678.html

最新回复(0)