Description
掌管着世界的暗流的是一个叫做Samjia的人。
他看到所有人的生死,他看见所有人一世又一世的轮回,而他却从未把握过自己的命。
在无法估计的命中,他看见那些轮回,他很好奇,这一切的一切,都是如何开始如何结束,他想,就算是他也会堕入这样的轮回中的吧。
于是他开始数轮回,他看到的是一个有n个点m条边的无向图(边是带标号的),一个轮回是一个由四条边组成的环,环中不能有重复的边,除了起点和终点外(当然,由于是一个环,起点和终点是一样的)不能经过一个同样的点多次。两个轮回被视为不同的当且仅当两个轮回各自的4条边中有一条的编号不同,Samjia想知道,这个system中有多少不同的轮回。
他忙着思考人生,所以数轮回的任务就交给你了。
Solution
大概思路就是枚举其中三个点,然后计算方案数。
这道题目用到了一种很实用的思想,我们枚举一个点
i
,枚举它的下一个点
Proof
假设一个点的大于等于这个点度数的点数为
x
,而这样的一幅图的边数最大为
我们把方案数挂在
k
点上,能够成为答案的方案一定包含从
Code
#include<algorithm>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,x) for(i=la[x];i;i=ne[i])
typedef long long ll;
const int N=5e4+5,maxn=1e6+5;
int la[N],ne[maxn*2],da[maxn*2],a[N],t[N],du[N],lv[N],wz[N],d[N];
int n,m,sum,i,j,k,x,y;
ll ans;
bool p[N];
void ins(int x,int y){
da[++sum]=y,ne[sum]=la[x],la[x]=sum;
}
int main(){
freopen("palingenesis.in","r",stdin);
freopen("palingenesis.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,m){
scanf("%d%d",&x,&y);
du[x]++,du[y]++;
ins(x,y),ins(y,x);
}
fo(i,1,n) t[du[i]]++;
fo(i,1,n) t[i]+=t[i-1];
for(i=n;i>0;i--)
lv[i]=t[du[i]]--;
fo(i,1,n){
sum=0;
memset(wz,0,sizeof(wz));
rep(j,i) if(lv[i]<lv[da[j]]){
rep(k,da[j])
if(lv[i]<lv[da[k]]){
if(i==da[k]) continue;
if(!wz[da[k]]){
d[++sum]=0;wz[da[k]]=sum;
}
d[wz[da[k]]]++;
}
}
fo(j,1,sum) ans+=d[j]*(d[j]-1)/2;
}
printf("%lld\n",ans);
}