计蒜客信息学赛前 CSP-S2 模拟赛 2
本来想打打计蒜客的比赛涨涨信心的,结果\(T2\)少考虑了一点东西给我整自闭了。
\(A\)
按位与的性质是,\(a \& b <= a\),所以某个点的距离就是所有直接与它相连的边的边权。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1000000;
int n, head[N + 50], num, dp[N + 50];
template <class T>
void Read(T &x)
{
x = 0; int p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
template <class T>
void Print(T x)
{
if (x > 9) Print(x / 10);
putchar(x % 10 + '0');
return;
}
void File()
{
freopen("node.in", "r", stdin);
freopen("node.out", "w", stdout);
return;
}
struct Node
{
int next, to, dis;
} edge[N * 2 + 50];
void Addedge(int u, int v, int w)
{
edge[++num] = (Node){head[u], v, w};
head[u] = num;
return;
}
void Dfs(int x, int fa, int fadis)
{
int maxx = fadis;
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
if (v == fa) continue;
maxx = max(maxx, edge[i].dis);
Dfs(v, x, edge[i].dis);
}
dp[x] = maxx;
return;
}
int main()
{
// File();
Read(n);
for (int i = 1, u, v, w; i <= n - 1; i++)
{
Read(u); Read(v); Read(w);
Addedge(u, v, w); Addedge(v, u, w);
}
Dfs(1, 0, 0);
int pos = 1;
for (int i = 2; i <= n; i++) if (dp[i] < dp[pos]) pos = i;
printf("%d", pos);
return 0;
}
\(B\)
考虑只有\(> k\)的\(n - k\)个点会对答案产生影响,所以令\(m - n - k\),将这\(m\)个点和剩下\(k\)个点分开来讨论。
定义一段连续的放在一起的\(> k\)的点为连通块,那么最后删去的边的数量就是\(n - k -\)连通块个数。
这样就可以枚举连通块个数算算贡献。
当把这\(m\)个点分成若干块时,剩下的\(k\)个点也需要分成\(k\)块,所以最多可以分成\(min(k, m - d)\)块。
枚举最后分成的块数\(p\),那么先用隔板法分成若干个集合\(\binom{m - 1}{p - 1}\)和\(\binom{k - 1}{p - 1}\),再枚举集合内部的情况乘上\(m!\)和\(k!\)。
然后因为环上的每个位置是不同的,所以再枚举哪个数开头将答案\(\times n\)。
但是发现之前划分集合的时候,因为集合是没有区分的,所以每种方案一共算了\(p\)次,答案要除以\(p\)。
这样最后就是
\[\sum_{p = 1}^{min(k, m - d)} \frac{\binom{m - 1}{p - 1} \binom{k - 1}{p - 1} \times m! \times k! \times n}{p}
\]
考试的时候就差了最后除以\(p\)那一步,难受。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1000000;
const int MOD = 998244353;
template <class T>
void Read(T &x)
{
x = 0; int p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
template <class T>
void Print(T x)
{
if (x > 9) Print(x / 10);
putchar(x % 10 + '0');
return;
}
int jc[N + 50], divjc[N + 50], n, k, d, div[N + 50];
int Zh(int n, int m)
{
return 1LL * jc[n] * divjc[n - m] % MOD * divjc[m] % MOD;
}
int Ksm(int a, int b)
{
int tmp = 1;
while (b)
{
if (b & 1) tmp = 1LL * tmp * a % MOD;
a = 1LL * a * a % MOD;
b >>= 1;
}
return tmp;
}
void File()
{
freopen("ring.in", "r", stdin);
freopen("ring.out", "w", stdout);
return;
}
int main()
{
// File();
int t;
Read(t);
jc[0] = 1;
for (int i = 1; i <= N; i++) jc[i] = 1LL * jc[i - 1] * i % MOD;
divjc[N] = Ksm(jc[N], MOD - 2);
for (int i = N - 1; i >= 0; i--) div[i + 1] = 1LL * divjc[i + 1] * jc[i] % MOD, divjc[i] = 1LL * divjc[i + 1] * (i + 1) % MOD;
divjc[0] = div[0] = 1;
while (t--)
{
Read(n); Read(k); Read(d);
int m = n - k, ans = 0;
for (int i = 1; i <= m - d; i++)
ans = (0LL + ans + 1LL * Zh(m - 1, i - 1) * Zh(k, i - 1) % MOD * div[i] % MOD) % MOD;
ans = 1LL * ans * n %MOD * jc[m] % MOD * jc[k] % MOD;
printf("%d\n", ans);
}
return 0;
}
/*
1
4 2 1
16
*/