常识:
组合意义就是有一个长为 m 的序列,每个点刷 n 种颜色,枚举最后有几中颜色
把 代上去
用归纳法证明
第 项的系数是
同样代
TCO14 CountTables
用 表示 m 列的答案,先强制行不相等,再减去列相等的情况
题解:[HDU4625] JZPTREE 一道比较妙的斯特林转下降幂的题
题解:HackerRank costly graphs 同样用斯特林转下降幂
CyclesNumber 求所有长度为 n 的置换的循环个数的 m 次方和。
令 表示循环 i 是否存在,那么一个置换求的就是
同样用斯特林化简
也就是说某 k 个循环同时存在对答案的贡献为
考虑如何求某 k 个循环同时存在的方案数,我们可以选出 k 个循环然后将剩下的破开与 n+1 再形成一个循环,方案数为
所以
当然 用斯特林化简
也是同样的结果
CodeChef-SUMCUBE
令 表示 i 这条边是否在 S 中
那么求的就是
考虑 k 条边,它们同时存在,对答案的贡献是
同时存在当且仅当 S 包涵了它们端点的并集,并集大小为 ,方案数就为
关于 算贡献的理解:
首先需要知道
在这道题中,暴力做法是先枚举点集,再知道之中的边数
对答案的贡献是
也就是说,从 x 中选 k 个出来算一下贡献
反过来想,就是在集合中任选 k 个,加上 的贡献,而正好会算
次
也就是说答案可以表示为 ,
是 k 条边的并集
于是可以枚举 k 条边 ,每 k 条同时存在的边会被算 次
显然不能枚举 k 条边是什么
我们分,分别统计两端并集大小为
的方案数
中间需要用到 3 元环计数:
如果 或
那么 x 向 y 连一条边
然后枚举 x,将它的出点标记成 x,然后取它的一个出点,对于出点的出点看一下标记是不是 x
由于我们的建边方式,每个三元环只会被统计一次
复杂度:每条边对复杂度的贡献是
如果 那么复杂度最多
如果 , 那么
,x 不会超过
个,也就是说每一个
的贡献最大就是
,而
,所以复杂度是
#include<bits/stdc++.h>
#define N 100050
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;
}
typedef long long ll;
const 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;}
int power(int a, int b, int ans = 1){
if(!ans) return 0;
for(;b;b>>=1){ if(b&1) ans = mul(ans, a); a = mul(a, a);}
return ans;
}
const int inv2 = (Mod + 1) / 2, inv3 = (Mod + 1) / 3, inv6 = mul(inv2, inv3);
int c2(int n){ return mul(mul(n, n-1), inv2);}
int c3(int n){ return mul(mul(n, n-1), mul(n-2, inv6));}
int s[4][4] = {{1}, {0, 1}, {0, 1, 1}, {0, 1, 3, 1}};
int *S;
int n, m, k, ans, d[N];
vector<int> E[N], G[N];
int calc2(){
int t1 = 0, t2 = c2(m);
for(int i = 1; i <= n; i++) t1 = add(t1, c2(d[i]));
t2 = add(t2, Mod - t1);
return mul(S[2] + S[2], add(power(2, n - 3, t1), power(2, n - 4, t2)));
}
bool cmp(int u, int v){ return d[u] > d[v] || (d[u] == d[v] && u > v);}
int vis[N], idx;
int ring(){
int cnt = 0;
for(int u = 1; u <= n; u++){
for(int i = 0; i < E[u].size(); i++){
int v = E[u][i]; if(cmp(u, v)) G[u].push_back(v);
}
}
for(int u = 1; u <= n; u++){
++idx;
for(int i = 0; i < G[u].size(); i++) vis[G[u][i]] = idx;
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
for(int j = 0; j < G[v].size(); j++) if(vis[G[v][j]] == idx) ++cnt;
}
} return cnt;
}
int calc3(){
int t1 = ring(), t2 = 0, t3 = 0, t4 = c3(m);
for(int u = 1; u <= n; u++)
for(int i = 0; i < G[u].size(); i++) t2 = add(t2, mul(d[u]-1, d[G[u][i]]-1));
t2 = add(t2, Mod - mul(t1, 3));
t3 = add(t3, Mod - add(t2, t2));
for(int u = 1; u <= n; u++){
t2 = add(t2, c3(d[u]));
t3 = add(t3, mul(m - d[u], c2(d[u])));
}
t3 = add(t3, Mod - mul(t1, 3));
t4 = add(t4, Mod - add(add(t1, t2), t3));
int t = mul(S[3], 6);
return mul(t, add(add(power(2, n-3, t1), power(2, n-4, t2)), add(power(2, n-5, t3), power(2, n-6, t4))));
}
void FSY(){
for(int i = 1; i <= n; i++) G[i].clear(), E[i].clear(), d[i] = 0;
}
void Yolanda(){
n = read(), m = read(), k = read(); S = s[k];
for(int i = 1; i <= m; i++){
int u = read(), v = read();
E[u].push_back(v); E[v].push_back(u);
++d[u]; ++d[v];
}
ans = mul(mul(m, S[1]), power(2, n - 2));
if(k > 1 && m > 1) ans = add(ans, calc2());
if(k > 2 && m > 2) ans = add(ans, calc3());
cout << ans << '\n';
}
int main(){
int T = read();
while(T--) Yolanda(), FSY(); return 0;
}