参考自大佬WA是一笔财富思路和代码,以下为自我理解,有不正确的地方还请纠正
题目链接:Double Profiles
题意:给定n(1 ≤ n ≤ 10^6)个点,m(0 ≤ m ≤ 10^6)条边,问有多少对(i,j)满足i!=j并且i,j的临接表相同
题解:我们可以将每个点用hash映射成对应数字,然后就可以用一个数字描述每个点的邻接表(点的hash值相加),对于图中所有点对我们可以分两种情况讨论
1.一种是两个点有边直接相连,那么就要求两者把自己加入双方邻接表后两者邻接表相等
2.另一种是两个点无边连接,那么就要求两者邻接表相等
分类判断下即可
细节和不懂见代码及注释:
#include<iostream>
#include<stack>
#include<list>
#include<set>
#include<vector>
#include<algorithm>
#include<math.h>
#include<numeric>
#include<map>
#include<cstring>
#include<queue>
#include<iomanip>
#include<cmath>
#include<queue>
#include <bitset>
#include<unordered_map>
#ifndef local
#define endl '\n'
#endif */
#define mkp make_pair
using namespace std;
using std::bitset;
typedef long long ll;
typedef long double ld;
const int inf=0x3f3f3f3f;
const ll MAXN=2e6+10;
const ll N=1e6+100;
const ll mod=1e9+7;
const ll hash_p1=1610612741;
const ll hash_p2=805306457;
const ll hash_p3=402653189;
//-----------------------------------------------------------------------------------------------------------------*/
// ll head[MAXN],net[MAXN],to[MAXN],edge[MAXN]/*流量*/,cost[MAXN]//费用;
/*
void add(ll u,ll v,ll w,ll s){
to[++cnt]=v;net[cnt]=head[u];edge[cnt]=w;cost[cnt]=s;head[u]=cnt;
to[++cnt]=u;net[cnt]=head[v];edge[cnt]=0;cost[cnt]=-s;head[v]=cnt;
}
struct elemt{
int p,v;
};
struct comp{
public:
bool operator()(elemt v1,elemt v2){
return v1.v<v2.v;
}
};
-----------------------------------
求[1,MAXN]组合式和逆元
ll mi(ll a,ll b){
ll res=1;
while(b){
if(b%2){
res=res*a%mod;
}
a=a*a%mod;
}
return res;
}
ll fac[MAXN],inv[MAXN]
fac[0]=1;inv[0]=1;
for(int i=1;i<=MAXN;i){
fac[i]=(fac[i-1]*i)%mod;
inv[i]=mi(fac[i],mod-2);
}
ll C(int m,int n){//组合式C(m,n);
if(!n){
return 1;
}
return fac[m]*(inv[n]*inv[m*-n]%mod)%mod;
}
---------------------------------
unordered_map<int,int>mp;
//优先队列默认小顶堆 , greater<int> --小顶堆 less<int> --大顶堆
priority_queue<elemt,vector<elemt>,comp>q;
set<int>::iterator it=st.begin();
*/
// vector<vector<int>>edge; 二维虚拟储存坐标
//-----------------------------------------------------------------------------------------------------------------*/
//map<int,bool>mp[N];
ll base=1331;//hash种子
ll h[N];//点映射hash值
ll hsh[N];//邻接表映射hash值
int x[N],y[N];
void init(){
h[0]=1;
for(int i=1;i<=N-5;i++){
h[i]=h[i-1]*base;
}
}
int main(){
/*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
/*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
init();
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x[i]>>y[i];
hsh[x[i]]+=h[y[i]];//将y放入x邻接表
hsh[y[i]]+=h[x[i]];//将x放入y邻接表
}
ll ans=0;
//分两种情况处理,
for(int i=1;i<=m;i++){
//一种是两个点有边直接相连,那么就要求两者把自己加入双方邻接表后两者邻接表相等
ll ha=hsh[x[i]]+h[x[i]],hb=hsh[y[i]]+h[y[i]];
if(ha==hb){
ans++;
}
}
//另一种是两个点无边连接,那么就要求两者邻接表相等
sort(hsh+1,hsh+n+1);//按hsh排序方便确定相等邻接表的个数
ll l=1;//左边界
for(int r=1;r<=n;r++){//枚举确定右边界(有点双指针的感觉了)
while(r+1<=n&&hsh[r+1]==hsh[l]){
r++;
}
ll len=r-l+1;//区间长度
ans+=len*(len-1)/2;//记录当前区间内组合方案数
l=r+1;
}
cout<<ans<<endl;
return 0;
}