command_block
2020-02-29 22:04:20
肯三竞赛·入门经典 - 多组赛配合理论 - 三元环
咳咳。
首先容易得到一个暴力 : 枚举3个点判断是否形成三元环,是
另一个暴力 : 枚举两条边判断两个外端点是否相连,复杂度
又一个暴力 : 枚举一个点及其对边,判断是否相连,复杂度
容易发现我们只是在不断暴力就得到了更优的复杂度,我们考虑继续暴力。
考虑给每条边定向(任意),把度数小的点连向度数大的点,度数相同则比较编号。
容易得知原图变成了一个DAG,则形如
我们要枚举
对于判定,可以事先把
神奇的是,枚举次数变为了
证明 :
枚举
它的出边必然指向比它大的点,出度最多也就
做
最多
现在,做一次
代码比较好写。
#include<algorithm>
#include<cstdio>
#include<vector>
#define sf scanf
#define MaxN 100500
using namespace std;
int n,m,du[MaxN],e[MaxN],ef,ans;
vector<int> g[MaxN];
struct Line{int f,t;}l[MaxN<<1];
void add(int x,int y)
{
if (du[y]>du[x]||(du[x]==du[y]&&y<x))
swap(x,y);
g[x].push_back(y);
}
int main()
{
sf("%d%d",&n,&m);
for (int i=1,f,t;i<=m;i++){
sf("%d%d",&l[i].f,&l[i].t);
du[l[i].f]++;du[l[i].t]++;
}for (int i=1;i<=m;i++)add(l[i].f,l[i].t);
for (int u=1;u<=n;u++){
ef=u;
for (int i=0;i<g[u].size();i++)
e[g[u][i]]=ef;
for (int i=0;i<g[u].size();i++)
for (int v=g[u][i],j=0;j<g[v].size();j++)
if (e[g[v][j]]==ef)ans++;
}printf("%d\n",ans);
return 0;
}
类似地建立DAG
则
也就是说,统计
至于怎么统计,一样考虑先枚举
最后把所有涉及到的点都拿出来统计即可。不难发现复杂度相同,为
题意 : 给出一张简单无向图,要求选出三个点互相之间没有边。
给定常数
考虑容斥。
设
二项式反演就得到