您的位置:首页 > 其它

【JZOJ5037】【NOI2017模拟3.30】轮回

2017-04-06 12:15 543 查看

任务

掌管着世界的暗流的是一个叫做Samjia的人。

他看到所有人的生死,他看见所有人一世又一世的轮回,而他却从未把握过自己的命。

在无法估计的命中,他看见那些轮回,他很好奇,这一切的一切,都是如何开始如何结束,他想,就算是他也会堕入这样的轮回中的吧。

于是他开始数轮回,他看到的是一个有n个点m条边的无向图(边是带标号的),一个轮回是一个由四条边组成的环,环中不能有重复的边,除了起点和终点外(当然,由于是一个环,起点和终点是一样的)不能经过一个同样的点多次。两个轮回被视为不同的当且仅当两个轮回各自的4条边中有一条的编号不同,Samjia想知道,这个system中有多少不同的轮回。

他忙着思考人生,所以数轮回的任务就交给你了。

对于100%的数据1<=n<=50000 1<=m<=100000

保证无重边和自环。

解法

首先有如下性质:

对于任意一张n个点m条边的图中,对于任意一个点,与它相连的并且度数不小于它的度数的点的连出去的边不超过m−−√条。

证明:

与它相连的并且度数不小于它的度数的点数是x,

那么这些点的度数就至少为x,连出去的边就是x2,就有x2<m,即x<m−−√。

于是这道题躺着做。

把点按度数排序后,依次寻找每个点走两步后到达任意一点i的路径数cnti,

然后答案就加上∑cnt2i。

代码

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<string.h>
#define ll long long
using namespace std;
const ll inf=0x7fffffff;
const char* fin="palingenesis.in";
const char* fout="palingenesis.out";
const ll maxn=100007,maxm=maxn*2;
ll n,m,i,j,k;
ll a[maxn],du[maxn];
ll fi[maxn],la[maxm],ne[maxm],tot;
ll az[maxn],ans=0,cnt[maxn],id=0;
bool bz[maxn];
void add_line(ll a,ll b){
tot++;
ne[tot]=fi[a];
la[tot]=b;
fi[a]=tot;
du[b]++;
}
bool cmp(ll a,ll b){return du[a]>du[b];}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
scanf("%lld%lld",&n,&m);
for (i=1;i<=n;i++) a[i]=i;
for (i=1;i<=m;i++){
scanf("%lld%lld",&j,&k);
add_line(j,k);
add_line(k,j);
}
sort(a+1,a+n+1,cmp);
for (i=1;i<=n;i++){
id++;
for (j=fi[a[i]];j;j=ne[j])
if (bz[la[j]]){
for (k=fi[la[j]];k;k=ne[k])
if (bz[la[k]]){
if (az[la[k]]<id){
az[la[k]]=id;
cnt[la[k]]=0;
}
ans-=(cnt[la[k]]*(cnt[la[k]]-1))/2;
cnt[la[k]]++;
ans+=(cnt[la[k]]*(cnt[la[k]]-1))/2;
}
}
bz[a[i]]=true;
}
printf("%lld",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: