【CodeChef】—Sum of Cubes(斯特林数+容斥+三元环计数)
令表示边在点集中是否出现
答案就是
考虑把次方拆开就是
考虑这个式子的组合意义,就是把一个置换的所有循环的集合的所有子集选出来
一个大小为的子集的贡献就是
就只需要把所有大小在以内的集合贡献求出来
考虑一个边的集合只需要考虑有哪些点必须选
剩下随便选或不选
一条边和两条边很好求
主要3条边
有5种情况
1、
2、
3、
4、
5、
5要用到三元环计数
然后依次推4、3、2、1,中间要容斥一下
然后就完了
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define pob pop_back
#define cs const
#define poly vector<int>
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=100005;
int s[4][4];
inline void init(){
s[0][0]=1;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
}
inline ll C3(int n){
return 1ll*(n-1)*(n-2)*n/6;
}
vector<int> e[N];
int n,m,k,in[N];
inline int solve1(){
if(n>=2)return mul(m,mul(ksm(2,n-2),s[k][1]));
else return 0;
}
inline int solve2(){
ll tot=0;int res=0;
for(int i=1;i<=n;i++)
for(int &v:e[i])tot+=in[v]-1;
tot/=2;
if(n>=3)Add(res,mul(tot%mod,mul(ksm(2,n-3),s[k][2])));
tot=1ll*m*(m-1)/2-tot;
if(n>=4)Add(res,mul(tot%mod,mul(ksm(2,n-4),s[k][2])));
return mul(res,2);
}
int cnt[N];
inline bool comp(int u,int v){
return (in[u]==in[v])?u>v:in[u]>in[v];
}
inline ll calc2(){
ll res=0;
for(int i=1;i<=n;i++)
res+=1ll*in[i]*(in[i]-1)/2*(m-2);
return res;
}
inline ll calc3(){
ll res=0;
for(int i=1;i<=n;i++)
for(int &v:e[i])
res+=1ll*(in[i]-1)*(in[v]-1);
return res/2;
}
inline ll calc4(){
ll res=0;
for(int i=1;i<=n;i++)
res+=C3(in[i]);
return res;
}
inline ll calc5(){
ll res=0;
for(int u=1;u<=n;u++){
for(int &v:e[u])if(comp(u,v))cnt[v]++;
for(int &v:e[u])if(comp(u,v))
for(int &z:e[v])if(comp(v,z))
if(cnt[z])res++;
for(int &v:e[u])if(comp(u,v))cnt[v]=0;
}
return res;
}
inline int solve3(){
ll cnt1=0,cnt2=0,cnt3=0,cnt4=0,cnt5=0;
cnt5=calc5(),cnt4=calc4(),cnt3=calc3()-cnt5*3;
cnt2=calc2()-cnt4*3-cnt5*3-cnt3*2,cnt1=C3(m)-cnt2-cnt3-cnt4-cnt5;
cnt1%=mod,cnt2%=mod,cnt3%=mod,cnt4%=mod,cnt5%=mod;
int res=0;
if(cnt1)Add(res,mul(cnt1,ksm(2,n-6)));
if(cnt2)Add(res,mul(cnt2,ksm(2,n-5)));
if(cnt3)Add(res,mul(cnt3,ksm(2,n-4)));
if(cnt4)Add(res,mul(cnt4,ksm(2,n-4)));
if(cnt5)Add(res,mul(cnt5,ksm(2,n-3)));
return mul(res,mul(s[k][3],6));
}
inline void solve(){
n=read(),m=read(),k=read();int res=0;
for(int i=1;i<=m;i++){
int u=read(),v=read();
in[u]++,in[v]++;
e[u].pb(v),e[v].pb(u);
}
if(1<=k)Add(res,solve1());
if(2<=k)Add(res,solve2());
if(3<=k)Add(res,solve3());
cout<<res<<'\n';
memset(in,0,sizeof(int)*(n+1));
for(int i=1;i<=n;i++)e[i].clear();
}
int main(){
init();
int T=read();
while(T--)solve();
}