AtCoder Beginner Contest 051
A
题意:
给一个逗号分割的字符串,改成空格分隔输出。
std::string s;
std::getline(std::cin, s);
for (auto &u : s) if (u == ',') u = ' ';
std::cout << s << "\n";
B
题意:
给一个 \(K, S\) 。询问满足 \(0 \leq \{X, Y, Z\} \leq K, X + Y + Z = S\) 的 \(|(X, Y, Z)|\) 。
\(2 \leq K \leq 2500, 0 \leq S \leq 3K\) 。
题解:
\(2500^{3}\) 能做吗?不能。但是可以枚举两个,算一个。 \(2500^{2}\) 能做吗?能。
注意没有规定顺序。
int K, S; std::cin >> K >> S;
int cnt = 0;
for (int i = 0; i <= K; i++) {
for (int j = 0; j <= K; j++) {
int z = S - i - j;
cnt += 0 <= z && z <= K;
}
}
std::cout << cnt << "\n";
考虑规定 \(0 \leq X \leq Y \leq Z \leq K, X + Y + Z = S\) ,询问 \(|(X, Y, Z)|\) 。则计算类似:
int cnt = 0;
for (int i = 0; i <= K; i++) {
for (int j = i; j <= K; j++) {
int z = S - i - j;
cnt += j <= z && z <= K;
}
}
甚至可以 \(O(S)\) 。
枚举 \(Z \in [0, S]\) ,得 \(L = S - Z = X + Y\) 。
尝试 \(O(1)\) 回答有 \(0 \leq X \leq Y \leq Z, X + Y = L\) 的二元组数。
考虑规定: \(X \in [l_X, r_X], Y \in [l_Y, r_Y], Z \in [l_Z, r_Z], X + Y + Z \geq S\) ,询问 \(|(X, Y, Z)|\) 。
还是可以 \(O(S)\) 做。
依然枚举 $Z \in [l_Z, r_Z] $, 得 \(L = X + Y \geq S - Z\) 。
怎么求 \(X + Y = L \ s.t.\ X \in [l_X, r_x], Y \in [l_Y, r_Y]\) 的 \(|(X, Y)|\) ?不容易直接算了(不是不能算)。
先说明这个东西是好算的,假设我们能提前求出上述的 \(f(L) = |(X, Y)| \ s.t.\ X + Y = L\) 。
再提前对 \(f\) 求前缀和 \(g\) ,\(g(L) = |(X, Y) \ s.t.\ X + Y \leq L |\) 。时间复杂度 \(O(S)\) 。
那么容斥 \(g(S) - g(L - 1)\) 即为 \(|(X, Y)| \ s.t. L = X + Y \geq S - Z\) 。
问题收束,\(f(L)\) 怎么求?一个好的性质是定义域连续。
for \(X^{'} \in [l_X, r_X]\) ,于是 \([X^{'} + l_Y, X^{'} + r_Y]\) 的位置都会被计算加 \(1\) 的贡献。
通过差分可以 \(O(S)\) 算出 \(f\) 数组的差分数组,求前缀和得到 \(f\) 。
总时间复杂度是 \(O(S)\) 。
C
题意:
海豚居住在二维笛卡尔坐标系上,坐标反向是从左下角往右上角看。海豚每一步可以向上、下、左、右走 \(1\) 的距离。
海豚一开始在 \((sx, sy)\) 点,然后会走到 \((tx, ty)\) ,然后回到 \((sx, sy)\) 。\(sx < tx, sy < ty\) 。
继续重复一次上述步骤。
除了 \((sx, sy)\) 和 \((tx, ty)\) ,海豚不能经过一次坐标多次。
询问任意一条路径通路,边的输出方式为“当前位置的下一步方向”。
比如:sx = 0, sy = 0, tx = 1, ty = 2 。一个答案为:UURDDLLUUURRDRDDDLLU 。
题解:
路径其实好找。
第一轮走任意两条除了端点外不相交的曼哈顿距离最短的路径,即在 \((sx, sy), (tx, ty)\) 确定的矩形 \(A\) 中选两条。
第一轮不妨贴着矩形 \(A\) 的边走。
第二轮无法在 \(A\) 中选路径,因为 \((sx, sy)\) 的两个度和 \((tx, ty)\) 的两个度被用完了。所以再往外一圈的矩形 \(B\) 中走曼哈段最短距离的路径。
第二轮不妨也贴着矩形 \(B\) 的边走。考虑在 \(B\) 内但不在 \(A\) 内的曼哈顿距离最短路径很显然。
int sx, sy, tx, ty; std::cin >> sx >> sy >> tx >> ty;
std::string ans = "";
ans += std::string(tx - sx, 'R');
ans += std::string(ty - sy, 'U');
ans += std::string(tx - sx, 'L');
ans += std::string(ty - sy, 'D');
ans += 'D';
ans += std::string(tx - sx + 1, 'R');
ans += std::string(ty - sy + 1, 'U');
ans += 'L';
ans += 'U';
ans += std::string(tx - sx + 1, 'L');
ans += std::string(ty - sy + 1, 'D');
ans += 'R';
std::cout << ans << "\n";
D
题意:
给一个 \(N\) 个点 \(M\) 条边的无向连通带权图,保证没有自环和重边。
第 \(i(1 \leq M)\) 条边连接节点 \(a_i\) 和 节点 \(b_i\) ,权值为 \(c_i\) 。
给一个 \(N, (N \leq 100)\) 个点 \(M\) 条边的无向带权连通图,没有自环和重边。第 \(i\) 条边连接点 \(a_i\) 和点 \(b_i\) 且距离为 \(c_i, (0 \leq c_i \leq 1000)\) 。找到不存在于任何最短路径中的边,计算它们的数量。
找到一类边的数量,满足这类边不在任意两个节点的可能的最短路径中。
连通图:任意节点互相可达。
\(1 \leq N \leq 100, N - 1 \leq M \leq min(\frac{N(N-1)}{2}, 1000)\)
\(1 \leq a_i, b_i, \leq N, 1 \leq c_i \leq 1000\)
题解:
和任意两点的最短路有关,先 \(O(n^{2})\) 冲个 Floyd 求出任意两点的最短路 \(dist_{u, v}\) 。
考虑一条无向边 \(e(a, b)\) ,如果在某两个点 \(u, v\) 的最乱路上,一定有 \(dist_{u, a} + w(a, b) + dist_{b, v} = dist{u, v}\) 或 \(dist_{u, b} + w(b, a) + dist_{a, v} = dist{u, v}\) 。
可以枚举每一条边 \(e(a, b)\) ,枚举两个点 \(u, v(\{u, v\} \cap \{a, b\} = \emptyset)\) 。若 \(e(a, b)\) 不在任意 \((u, v)\) 的最短路上,则 \(e(a, b)\) 加入解集 \(\mathbb{S}\) 。最终 \(|\mathbb{S}|\) 是答案。时间复杂度 \(O(n^{2} m)\) 。
事实上,任意两个点 \(u, v\) 的某条最短路径 \(r\) ,去除一个端点后依旧是一条最短路径。否则可以在 \(u, v\) 间构造出一条比 \(r\) 更短的路径。
这意味着任意两个点 \(u, v\) 的某条最短路径,首位去除若干连续个点后依旧一条最短路径。
所以,枚举任意一条边 \(e(a, b)\) ,只用枚举一个点 \(u(u \neq a, b)\) 。检查 \(u\) 到 \(a\) 或 \(b\) 的最短路是否经过 \(e(a, b)\) 即可。
当任意点 \(u\) 到 \(a\) 或 \(b\) 的最短路都不经过过 \(e(a, b)\) ,则 \(e(a, b)\) 加入解集 \(S\) 。
chek 所有边的时间复杂度为 \(O(m n)\) 。
于是总时间复杂度为 \(O(n^{3} + n m)\) 。
int N, M; std::cin >> N >> M;
std::vector<std::vector<int> > w(N + 1, std::vector<int>(N + 1));
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (i == j) w[i][j] = 0;
else w[i][j] = inf;
}
}
std::vector<std::array<int, 2> > e(M + 1, {0, 0});
for (int i = 1; i <= M; i++) {
int u, v, wight; std::cin >> u >> v >> wight;
e[i] = {u, v};
w[u][v] = std::min(w[u][v], wight);
w[v][u] = std::min(w[v][u], wight);
}
std::vector<std::vector<int> > dist = w;
for (int k = 1; k <= N; k++) {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (dist[i][k] != inf && dist[k][j] != inf && dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
int cnt = 0;
for (int i = 1; i <= M; i++) {
int ok = 0;
for (int j = 1; j <= N; j++) {
ok |= (dist[j][e[i][0]] + w[e[i][0]][e[i][1]] == dist[j][e[i][1]] || dist[j][e[i][1]] + w[e[i][1]][e[i][0]] == dist[j][e[i][0]]);
}
if (!ok)
cnt += 1;
}
std::cout << cnt << "\n";
浙公网安备 33010602011771号