题目
Given an undirected simple graph with n (n ≥ 3) vertices and m edges where the vertices are numbered from 1 to n, we call it a "sub-cycle" graph if it's possible to add a non-negative number of edges to it and turn the graph into exactly one simple cycle of n vertices.
Given two integers n and m, your task is to calculate the number of different sub-cycle graphs with n vertices and m edges. As the answer may be quite large, please output the answer modulo 109 + 7.
Recall that
- A simple graph is a graph with no self loops or multiple edges;
- A simple cycle of n (n ≥ 3) vertices is a connected undirected simple graph with n vertices and n edges, where the degree of each vertex equals to 2;
- Two undirected simple graphs with n vertices and m edges are different, if they have different sets of edges;
- Let u < v, we denote (u, v) as an undirected edge connecting vertices u and v. Two undirected edges (u1, v1) and (u2, v2) are different, if u1 ≠ u2 or v1 ≠ v2.
input
There are multiple test cases. The first line of the input contains an integer T (about 2 × 104), indicating the number of test cases. For each test case:
The first and only line contains two integers n and m (3 ≤ n ≤ 105,
), indicating the number of vertices and the number of edges in the graph.
It's guaranteed that the sum of n in all test cases will not exceed 3 × 107.
output
For each test case output one line containing one integer, indicating the number of different sub-cycle graphs with n vertices and m edges modulo 109 + 7.
题目大意
定义一个简单子环图为:一个 n 个点, m 条边的简单图,可以通过添加若干非负整数条边,使得整个图变成一个 n个点的简单环图。
给定 n 和 m ,表示一个 n 个点, m 条边的简单图,问一共有多少种 n个点 m 条边的简单子环图。
思路
sub-cycle graph 可以理解为每个连通块都是一个点或者一条链(显然环也是可以的)。
可以对一下情况进行一些讨论:
1、,边数大于点数,显然无解。
2、,此时图是一整个环,显然图的种类是
可以以任意一个点为起始点,然后接下来的情况就是每个点分别能连n-1,n-2……,1种,
总数是,除以2是因为顺时针逆时针是重复的。
3、,显然方案唯一
4、剩下来的情况,也就是 的情况,由于每个连通块中都不能存在环,因此我们建的图需要有 个连通块。
首先枚举联通块存在i条链,相当于存在个孤立点,方案数是,然后从剩下的个点中去找个点,方案数是,然后将这些点两两分组,用隔板法,方案数就是, 然后还需要继续考虑除了链端点以外的节点,将剩下的点全排列并分成i份,方案数是
所以总的方案就是
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+100;
const int mod = 1e9+7;
int P1[N],P2[N];
int ksm(int a,int b) {
int ans=1;
while(b) {
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init(int tot) {
P1[0]=1;
for(int i=1; i<=tot; i++)P1[i]=1ll*P1[i-1]*i%mod;
P2[tot]=ksm(P1[tot],mod-2);
for(int i=tot-1; i>=0; i--)P2[i]=1ll*P2[i+1]*(i+1)%mod;
}
int C(int n,int m) {
return 1ll*P1[n]*P2[m]%mod*P2[n-m]%mod;
}
void solve() {
int x,y;
cin>>x>>y;
if (y==0) {
cout<<"1\n";
} else if (y>x) {
cout<<"0\n";
} else if (x==y) {
cout<<P1[x-1]*P2[2]%mod<<'\n';
} else {
int ans=0;
int p=1;
for(int i=1; i<=x-y; i++) {
if (y+i<i*2) continue;
int k=C(y+i,i*2)*p%mod;
p=p*(i*2+1)%mod;
k=k*P1[y-i]%mod;
k=k*C(y-1,i-1)%mod;
ans=(ans+C(x,x-y-i)*k)%mod;
}
cout<<ans<<'\n';
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init(200000);
int t=1;
cin>>t;
while(t--)solve();
return 0;
}