题意: 个点, 条边,求包含 条边的联通块个数
,显然为
,枚举中间点组合数算即可
,有三种情况,一种是三元环,一种是链,一种是菊花图
链:枚举中间边,算两边的贡献,但两边的出点重合会退化为三元环
每个三元环会算三次,菊花图枚举根算,然后三元计数把多的减掉
发现共 5 种情况
第 3 个组合数算
第 4 个可以求出每个点所在的三元环个数然后枚举点算贡献
第 2 个可以枚举边
,然后算 2 和 3 出去 1 个或 2 个的贡献,
当 1,4 或者 1,5 重合的时候回退化为 4,多算了两边需要减掉
第 1 个可以枚举 3,然后按顺序枚举 3 的出边,考虑当前边与之前的拼接
但退化有点烦
当 1 和 4 重合 或者是 2 和 5 重合会被多算,在图 4 中会在 3,4 被多算两次
当 1 5 重合会退化成 5,多算了 4 次
当 1 4 并且 2 5 重合会被算到三元环里面,多算 3 次
现在问题就是如何求四元环个数
依然按照三元环那样排序,我们定义 4 元环“权值”最大为根
需要保证一个四元环只会在最大的根算一次
枚举根以及出边,然后枚举出边的出点,对每个到根路径为 2 的点维护条数,加上之前的条数过后将条数加 1,然后再倒过来加一遍就可以把每一个点的贡献算上
代码奉上:
static int ct[N], sm[N];
for(int i=1; i<=n; i++){
for(int j=0; j<v[i].size(); j++)
if(cmp(i,v[i][j])){
for(int e=0,t=v[i][j]; e<v[t].size(); e++)
if(cmp(i,v[t][e])){
int w = v[t][e];
sm[i]+=ct[w]; sm[t]+=ct[w]; sm[w]+=ct[w]; ++ct[w];
}
}
for(int j=0; j<v[i].size(); j++)
if(cmp(i,v[i][j])){
for(int e=0,t=v[i][j]; e<v[t].size(); e++)
if(cmp(i,v[t][e])){
int w = v[t][e]; sm[t] += --ct[w];
}
}
} int ans = 0;
for(int i = 1; i <= n; i++) Add(ans, sm[i]);
return mul(ans, inv4);
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e5 + 5, M = 2e5 + 5;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b); }
cs int inv2 = (Mod+1)>>1, inv3 = (Mod+1)/3, inv6 = mul(inv2,inv3);
cs int inv4 = mul(inv2, inv2), inv24 = mul(inv4,inv6);
int n, m, k, x[M], y[M];
vector<int> v[N], A[N];
int C2(int x){ return mul(inv2, mul(x,x-1)); }
int C3(int x){ return mul(mul(inv6, x), mul(x-1, x-2)); }
int C4(int x){ return mul(mul(inv24, mul(x,x-1)), mul(x-2,x-3));}
namespace Subtask2{
void Solve(){
int ans = 0;
for(int i=1; i<=n; i++) Add(ans, C2(v[i].size()));
cout << ans;
}
}
bool cmp(int x, int y){ return v[x].size() > v[y].size() || (v[x].size() == v[y].size() && x > y); }
int cir[N];
int Circle3(){
int ans = 0;
for(int i=1; i<=m; i++){
if(cmp(x[i], y[i])) A[x[i]].push_back(y[i]);
else A[y[i]].push_back(x[i]);
}
static int vis[N]; int TIME = 0;
memset(vis, 0, sizeof(vis));
memset(cir, 0, sizeof(cir));
for(int i=1; i<=n; i++){
++TIME;
for(int j=0; j<A[i].size(); j++) vis[A[i][j]] = TIME;
for(int j=0; j<A[i].size(); j++)
for(int e=0,v=A[i][j]; e<A[v].size(); e++)
if(vis[A[v][e]] == TIME) ++ans, ++cir[i], ++cir[v], ++cir[A[v][e]];
} return ans;
}
namespace Subtask3{
void Solve(){
int ans = 0;
for(int i=1; i<=n; i++) Add(ans, C3(v[i].size()));
for(int i=1; i<=m; i++) Add(ans, mul(v[x[i]].size()-1, v[y[i]].size()-1));
Add(ans, Mod-mul(2,Circle3())); cout << ans;
}
}
int Circle4(){
static int ct[N], sm[N];
for(int i=1; i<=n; i++){
for(int j=0; j<v[i].size(); j++)
if(cmp(i,v[i][j])){
for(int e=0,t=v[i][j]; e<v[t].size(); e++)
if(cmp(i,v[t][e])){
int w = v[t][e];
sm[i]+=ct[w]; sm[t]+=ct[w]; sm[w]+=ct[w]; ++ct[w];
}
}
for(int j=0; j<v[i].size(); j++)
if(cmp(i,v[i][j])){
for(int e=0,t=v[i][j]; e<v[t].size(); e++)
if(cmp(i,v[t][e])){
int w = v[t][e]; sm[t] += --ct[w];
}
}
} int ans = 0;
for(int i = 1; i <= n; i++) Add(ans, sm[i]);
return mul(ans, inv4);
}
namespace Subtask4{
int calc(){
int ans = 0;
for(int i=1; i<=n; i++) Add(ans, mul(cir[i], (int)v[i].size()-2));
return ans;
}
void Solve(){
int ans = 0;
Add(ans, Mod-mul(3,Circle3()));
for(int i=1; i<=n; i++) Add(ans, C4(v[i].size()));
for(int i=1; i<=m; i++)
Add(ans, mul(C2(v[x[i]].size()-1),v[y[i]].size()-1)),
Add(ans, mul(C2(v[y[i]].size()-1),v[x[i]].size()-1));
Add(ans, Mod-mul(3,calc()));
for(int i=1; i<=n; i++){
int coe = 0;
for(int e=0; e<v[i].size(); e++){
int u = v[i][e];
Add(ans,mul(coe, v[u].size()-1));
Add(coe, v[u].size()-1);
}
}
Add(ans, Mod-mul(3,Circle4()));
cout << ans;
}
}
int main(){
n = read(), m = read(), k = read();
for(int i = 1; i <= m; i++){
x[i] = read(), y[i] = read();
v[x[i]].push_back(y[i]);
v[y[i]].push_back(x[i]);
}
if(k == 1){ cout << m; return 0; }
if(k == 2){ Subtask2::Solve(); return 0;}
if(k == 3){ Subtask3::Solve(); return 0;}
if(k == 4){ Subtask4::Solve(); return 0;}
}