#include using namespace std; #define int long long #define endl "\n" const int M = 1e2 + 7; const int P = 1e9 + 7; int T, n, m, cas = 1; int g[M][M]; int fac[M]; // 快速幂 int qmi(int a, int b) { int res = 1; a %= P; while (b) { if (b & 1) res = res * a % P; b >>= 1; a = a * a % P; } return res; } /* Q:什么是费马小定理? 答:费马小定理是一个关于模运算的定理,它陈述了如果p是一个质数,而a是任意整数且不是p的倍数, 那么a^(p-1) 与 1 (mod p) 同余。 Q:费马小定理是怎么求逆元的? 答:当p是质数时,我们分离一项出来 a * a^(p−2) ≡ 1 (mod p) 对比逆元的方程式,可以很容易得到,a关于p的逆元就是 a^(p −2),而a^(p-2)可以用快速幂求得 Q:组合数公式C(n,m)=n!/(m!*(n-m)!) ,由于需要取模,同时存在除法,所以可以考虑是否可以用费马小定理求除法逆元? 答:是可以的,原因:因为模mod=1e9+7是质数,并且,题目中的数据范围n<=50,是不可能是mod的倍数的,所以符合费马小定理 的要求,可以用费马小定理来求除法逆元。 */ int C(int n, int m) { /* fac[n]: n! qmi(fac[m], P - 2) : 费马小定理的结果 (m!)^(p-2),这样,把除m!取模 转化为乘 (m!)^(p-2)后取模 qmi(fac[n - m], P - 2) :同上 */ return fac[n] * qmi(fac[m], P - 2) % P * qmi(fac[n - m], P - 2) % P; } int judge3(int i, int j, int k) { // 判断三点之间满不满足不稳定点集 if (g[i][j] && g[i][k] && g[j][k]) return 1; // 三点之间相连 if (!g[i][j] && !g[i][k] && !g[j][k]) return 1; // 三点之间不互连 return 0; } int judge4(int i, int j, int k, int l) { if (judge3(i, j, k) || judge3(i, j, l) || judge3(j, k, l) || judge3(i, k, l)) return 1; // 表示4个点中有三个点为不稳定点集就行,为什么呢? // 因为时题目要求的,不稳定点集为3个点。 return 0; } int judge5(int i, int j, int k, int l, int o) { // 表示5个点中有4个点满足就行 if (judge4(i, j, k, l) || judge4(i, j, k, o) || judge4(i, j, l, o) || judge4(j, k, l, o) || judge4(i, k, l, o)) return 1; return 0; } void solve() { cin >> n >> m; // n个顶点,m条边 memset(g, 0, sizeof g); // 初始化地图 while (m--) { int a, b; cin >> a >> b; g[a][b] = g[b][a] = 1; // 无向图 } int ans = 0; if (n >= 6) { ans = qmi(2, n); // ① 多项式定理C(n,0)+C(n,1)+...+C(n,n)=2^n // ② 也可以这样来思考,一个也不要,要1个,要2个,要3个,...,要n个 // C(n,k)(k>=6)表示,从n个中取k个出来,总存在一个不稳定点集的个数(三点之间互联或三点之间不连) for (int i = 0; i < 6; i++) /// 减去前5个 ans = (ans - C(n, i) + P) % P; } if (n >= 3) { // 枚举任意3个 for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) for (int k = j + 1; k <= n; k++) if (judge3(i, j, k)) ans = (ans + 1) % P; } if (n >= 4) { // 暴力取4个 for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) for (int k = j + 1; k <= n; k++) for (int l = k + 1; l <= n; l++) if (judge4(i, j, k, l)) ans = (ans + 1) % P; } if (n >= 5) { // 暴力取5个 for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) for (int k = j + 1; k <= n; k++) for (int l = k + 1; l <= n; l++) for (int o = l + 1; o <= n; o++) if (judge5(i, j, k, l, o)) ans = (ans + 1) % P; } printf("Case #%lld: %lld\n", cas++, ans); } signed main() { // 加快读入 ios::sync_with_stdio(false), cin.tie(0); // 预处理阶乘数组(同步取模) fac[0] = 1, fac[1] = 1; for (int i = 2; i < M; i++) fac[i] = fac[i - 1] * i % P; cin >> T; while (T--) solve(); }