接下来的问题就是什么时候可以统计答案。
显然是剩余的点恰好为 B 或 B+1 的时候。
对应一般情况和可以与某一个大小恰好为 B 的子树组合成一个连通块的情况。
另外,对于第二种情况的方案数:
v is a son of u,sizv=B∑w is a son of u,w=v∏dpw
考虑怎么统计这个东西。
我们考虑将贡献拆成两部分,对于满足 sizv=B 的点 v 统计其之前扫到的 w 对它的贡献,对于满足 sizw≥B 的点 w 统计其对之前的 v 的贡献。(这里用 v 和 w 分别表示两种节点,下同。)
对于当前点 v,所有在它之前被扫到的 w 的总贡献就是当前的 dpu。
对于当前点 w,相当于要之前的所有点的贡献都乘上 dpw,也就是当前的总贡献乘上 dpw。
int n, m, k, cnt; template<int N, int M> structgraph { int tot, hd[N]; int nxt[M], to[M];
voidadd(int u, int v){ nxt[++tot] = hd[u]; hd[u] = tot; to[tot] = v; return ; } }; graph<100005, 400005> g; graph<200005, 400005> tr; int timer, dfn[100005], low[100005]; stack<int> s; int ans, res, siz[200005], dp[200005], vis[200005];
voidTarjan(int now){ dfn[now] = low[now] = ++timer; s.push(now); for (int i = g.hd[now]; i; i = g.nxt[i]) if (!dfn[g.to[i]]) { Tarjan(g.to[i]); low[now] = min(low[now], low[g.to[i]]); if (low[g.to[i]] == dfn[now]) { cnt++; for (int x = 0; x != g.to[i]; s.pop()) { x = s.top(); tr.add(cnt, x); tr.add(x, cnt); } tr.add(cnt, now); tr.add(now, cnt); } } else low[now] = min(low[now], dfn[g.to[i]]); return ; } voidgetSize(int now, int fa){ siz[now] = (now <= n); for (int i = tr.hd[now]; i; i = tr.nxt[i]) if (tr.to[i] != fa) getSize(tr.to[i], now), siz[now] += siz[tr.to[i]]; return ; } voiddfs1(int now, int fa, constint &B){ if (now > n) { dp[now] = 1; for (int i = tr.hd[now]; i; i = tr.nxt[i]) if (tr.to[i] != fa) dfs1(tr.to[i], now, B), dp[now] = (longlong)dp[now] * dp[tr.to[i]] % mod; return ; } dp[now] = 1; int sum = 1; for (int i = tr.hd[now]; i; i = tr.nxt[i]) if (tr.to[i] != fa) { if (siz[tr.to[i]] < B) {sum += siz[tr.to[i]]; continue;} dfs1(tr.to[i], now, B); dp[now] = (longlong)dp[now] * dp[tr.to[i]] % mod; } if (n - (siz[now] - sum) == B) res = (res + dp[now]) % mod; dp[now] *= (sum == B); return ; } voiddfs2(int now, int fa, constint &B){ if (now > n) { dp[now] = 1; for (int i = tr.hd[now]; i; i = tr.nxt[i]) if (tr.to[i] != fa) dfs2(tr.to[i], now, B), dp[now] = (longlong)dp[now] * dp[tr.to[i]] % mod; return ; } dp[now] = 1; int sum = 1, num = 0; for (int i = tr.hd[now]; i; i = tr.nxt[i]) if (tr.to[i] != fa) { if (siz[tr.to[i]] < B) {sum += siz[tr.to[i]]; continue;} dfs2(tr.to[i], now, B); num = (longlong)num * dp[tr.to[i]] % mod; if (siz[tr.to[i]] == B) num = (num + dp[now]) % mod; dp[now] = (longlong)dp[now] * dp[tr.to[i]] % mod; } if (n - (siz[now] - sum) == B || n - (siz[now] - sum) == B + 1) res = (res + dp[now]) % mod; if (now == 1 && sum == 1) res = (res + num) % mod; dp[now] *= (sum == B || sum == B + 1); dp[now] += num * (sum == 1); return ; }
intmain(){ scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); g.add(u, v); g.add(v, u); } cnt = n; Tarjan(1); getSize(1, 0); if (k == 0) { for (int i = 1; i < n; i++) if (n % i == 0) { res = 0; memset(dp, 0, sizeof(dp)); dfs1(1, 0, i); ans = (ans + res) % mod; } } else { for (int i = 1; i <= n - 2; i++) { if (n % i > n / i) continue; res = 0; memset(dp, 0, sizeof(dp)); dfs2(1, 0, i); ans = (ans + res) % mod; vis[i]++, vis[i + 1]++; } for (int i = 1; i <= n - 2; i++) if (vis[i] >= 2) { res = 0; memset(dp, 0, sizeof(dp)); dfs1(1, 0, i); ans = (ans - res + mod) % mod; } } printf("%d\n", ans); return0; }