简要题意:
给 n n n 个点, m m m 条边的无向图,询问含有 k k k 条边的联通子图的个数
n ≤ 1 0 5 , m ≤ 2 ∗ 1 0 5 , k ≤ 4 n≤10^5,m≤2∗10^5,k≤4 n≤105,m≤2∗105,k≤4
题解:
容斥其实很简单,懒得讲了,如果你不知道这道题的容斥是怎么回事可以参见这里。
然后三元环的DAG建图计算方式和四元环的计算方式以及复杂度,我来这里给大家口胡一下
首先是三元环:
给所有边定向,从度数大的连向度数小的,度数相同按照编号从大到小连接。
显然连出来的图是一个DAG。
之后枚举每一个点 u u u ,然后将 u u u 的所有相邻的点打上标记,然后枚举 u u u 的出点 v v v ,再枚举 v v v的相邻的点 w w w,如果 w w w被打了标记,那么 ( u , v , w ) (u,v,w) (u,v,w) 就是一个三元环了。
而且我们能够保证每个三元环只记录了一次,这个算法的复杂度为
O
(
m
m
)
O(m\sqrt m)
O(mm),而且度数小的向度数大的连边也是
O
(
m
m
)
O(m\sqrt m)
O(mm)
复杂度证明也很简单:
我们发现复杂度瓶颈在于枚举长度为
2
2
2的路径上。
枚举次数显然为
∑
v
o
u
t
v
\sum_{v}out_v
∑voutv。
将
o
u
t
v
out_v
outv分类讨论
- o u t v ≤ m out_v≤m outv≤m,由于 u u u 连接 v v v , d u ≥ d v d_u \ge d_v du≥dv,这样的 u u u 的个数是 O ( n ) O(n) O(n) 的,因此这里的时间复杂度为 O ( n m ) O(n \sqrt m) O(nm)
- o u t v > m out_v \gt \sqrt m outv>m,由于 u u u 连接 v v v , d u ≥ d e g v d_u \ge deg_v du≥degv,即 d u > m d_u \gt \sqrt m du>m,这样的 u u u 的个数是 O ( m ) O(\sqrt m) O(m) 的,因此这里的时间复杂度为 O ( m m ) O(m\sqrt m ) O(mm)
然后是四元环,我们只需要把三元环的打标记过程改一下,改为在线。
具体表述为,我们不用DAG,而是直接建立原图,然后从度数大的点开始枚举,所有后继中有到他距离为2的点就 + = c n t [ v ] +=cnt[v] +=cnt[v],然后将这个点的 c n t + + cnt++ cnt++。
最后消除一下影响就行了。删掉这个度数最大的点,继续做。
复杂度的证明是一样的。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
re char c;
while(!isdigit(c=gc()));re T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Inc(int &a,int b){(a+=b)>=mod?a-=mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:a;}
inline int mul(int a,int b){return (ll)a*b>=mod?(ll)a*b%mod:(ll)(a*b);}
template<class ...Args>
inline int mul(int a,cs Args &...args){return mul(a,mul(args...));}
template<class ...Args>
inline int add(int a,cs Args &...args){return add(a,add(args...));}
cs int inv2=(mod+1)>>1,inv3=(mod+1)/3,inv4=mul(inv2,inv2),inv6=mul(inv3,inv2),inv24=mul(inv4,inv6);
inline int c2(int n){return mul(n,n-1,inv2);}
inline int c3(int n){return mul(n,n-1,n-2,inv6);}
inline int c4(int n){return mul(n,n-1,n-2,n-3,inv24);}
cs int N=1e5+5;
int n,m,k;
struct edge{int u,v;}E[N<<1];
std::vector<int> G[N];
inline void addedge(int u,int v){
G[u].push_back(v);
}
int d[N],d2[N],d3[N];
int r3[N],r4[N],cnt3,cnt4;
int vis[N];
inline bool cmp(int x,int y){return d[x]>d[y]||(d[x]==d[y]&&x>y);}
inline void calc_3(){
for(int re u=1;u<=n;++u){
for(int re v:G[u])++vis[v];
for(int re v:G[u])for(int re w:G[v])vis[w]&&(++r3[u],++r3[v],++r3[w]);
for(int re v:G[u])vis[v]=0;
}
for(int re u=1;u<=n;++u)Inc(cnt3,r3[u]);
cnt3=mul(cnt3,inv3);
}
inline void calc_4(){
for(int re u=1;u<=n;++u){
for(int re v:G[u])if(cmp(u,v))for(int re w:G[v])cmp(u,w)&&(r4[u]+=vis[w],r4[v]+=vis[w],r4[w]+=vis[w],++vis[w]);
for(int re v:G[u])if(cmp(u,v))for(int re w:G[v])cmp(u,w)&&(r4[v]+=--vis[w]);
}
for(int re u=1;u<=n;++u)Inc(cnt4,r4[u]);
cnt4=mul(cnt4,inv4);
}
inline void cal2(){
int ans=0;
for(int re i=1;i<=m;++i)++d[getint()],++d[getint()];
for(int re i=1;i<=n;++i)Inc(ans,c2(d[i]));
cout<<ans<<"\n";
}
inline void cal3(){
int ans=0;
for(int re i=1;i<=m;++i)++d[E[i].u=getint()],++d[E[i].v=getint()];
for(int re i=1;i<=m;++i)cmp(E[i].u,E[i].v)?addedge(E[i].u,E[i].v):addedge(E[i].v,E[i].u);
calc_3();
for(int re i=1;i<=n;++i)Inc(ans,c3(d[i]));
for(int re i=1;i<=m;++i)Inc(ans,mul(d[E[i].u]-1,d[E[i].v]-1));
Dec(ans,add(cnt3,cnt3));
cout<<ans<<"\n";
}
inline int calc(){
int res=0;
for(int re u=1;u<=n;++u)Inc(res,mul(r3[u],d[u]-2));
return res;
}
inline void cal4(){
int ans=0;
for(int re i=1;i<=m;++i)++d[E[i].u=getint()],++d[E[i].v=getint()];
for(int re i=1;i<=m;++i)cmp(E[i].u,E[i].v)?addedge(E[i].u,E[i].v):addedge(E[i].v,E[i].u);
calc_3();
for(int re i=1;i<=m;++i)cmp(E[i].u,E[i].v)?addedge(E[i].v,E[i].u):addedge(E[i].u,E[i].v);
calc_4();
for(int re i=1;i<=n;++i)Inc(ans,c4(d[i]));
for(int re i=1;i<=m;++i)Inc(ans,add(mul(c2(d[E[i].u]-1),d[E[i].v]-1),mul(c2(d[E[i].v]-1),d[E[i].u]-1)));
Dec(ans,mul(3,calc()));
for(int re u=1;u<=n;++u){
int t=0;
for(int re v:G[u])
Inc(ans,mul(t,d[v]-1)),
Inc(t,d[v]-1);
}
Dec(ans,mul(3,cnt3));
Dec(ans,mul(3,cnt4));
cout<<ans<<"\n";
}
signed main(){
n=getint(),m=getint(),k=getint();
switch(k){
case 1:cout<<m<<"\n";break;
case 2:cal2();break;
case 3:cal3();break;
case 4:cal4();break;
}
return 0;
}