题目描述
Babel Inc.\texttt{Babel Inc.}Babel Inc. 设计了一种由圆形截面柱体堆叠而成的塔结构。每个柱体的高度为单位长度 111,半径为 rkr_krk,材料均匀且不可变形。柱体从底部到顶部编号为 0,1,…,n−10, 1, \dots, n-10,1,…,n−1,其中柱体 000 放置在地面上,柱体 kkk(k≥1k \ge 1k≥1)放置在柱体 k−1k-1k−1 的上表面上,其质心位于 (xk,yk,k+0.5)(x_k, y_k, k + 0.5)(xk,yk,k+0.5)。
一个 nnn - 塔是 nnn 个柱体的堆叠。若在建造过程中(自底向上逐个添加柱体),每一步对应的子塔都是稳定的,则该塔是可行的。稳定性定义为:对于任意柱体 sss,所有堆叠在它上方的柱体(包括它自身)组成的子系统的合质心,必须严格位于柱体 s−1s-1s−1 的上表面圆盘内部(边界视为不稳定)。地面可视为半径无穷大的支撑面。
给定 NNN 个柱体的设计参数,判断该塔是否可行。若不可行,输出导致倒塌的柱体编号 kkk(满足 0<k<N0 < k < N0<k<N),即添加柱体 kkk 后首次出现不稳定。
输入格式
- 每个测试用例以整数 NNN(0<N<10000 < N < 10000<N<1000)开始。
- 接下来 NNN 行,每行三个整数 xk,yk,rkx_k, y_k, r_kxk,yk,rk,表示柱体 kkk 的质心水平坐标和半径。
- 输入以 N=0N = 0N=0 结束。
输出格式
- 若所有 NNN 个柱体添加后仍稳定,输出
Feasible。 - 否则,输出
Unfeasible k,其中 kkk 是第一个导致不稳定的柱体编号。
题目分析
物理模型
每个柱体的体积 Vk=πrk2⋅1V_k = \pi r_k^2 \cdot 1Vk=πrk2⋅1,由于材料均匀,质量 mk∝rk2m_k \propto r_k^2mk∝rk2。因此,在计算质心时,我们可以将每个柱体抽象为一个质点,位于其几何中心 (xk,yk,k+0.5)(x_k, y_k, k + 0.5)(xk,yk,k+0.5),权重为 wk=rk2w_k = r_k^2wk=rk2。
对于从柱体 sss 到柱体 ttt(s≤ts \le ts≤t)的子塔,其合质心的水平坐标为:
Xs,t=∑i=stwi⋅xi∑i=stwi,Ys,t=∑i=stwi⋅yi∑i=stwi X_{s,t} = \frac{\sum_{i=s}^t w_i \cdot x_i}{\sum_{i=s}^t w_i}, \quad Y_{s,t} = \frac{\sum_{i=s}^t w_i \cdot y_i}{\sum_{i=s}^t w_i} Xs,t=∑i=stwi∑i=stwi⋅xi,Ys,t=∑i=stwi∑i=stwi⋅yi
该子塔放置在柱体 s−1s-1s−1 的上表面上,支撑面的圆心为 (xs−1,ys−1)(x_{s-1}, y_{s-1})(xs−1,ys−1),半径为 rs−1r_{s-1}rs−1。稳定性条件为:
(Xs,t−xs−1)2+(Ys,t−ys−1)2<rs−12 \left( X_{s,t} - x_{s-1} \right)^2 + \left( Y_{s,t} - y_{s-1} \right)^2 < r_{s-1}^2 (Xs,t−xs−1)2+(Ys,t−ys−1)2<rs−12
判断流程
建造过程自底向上进行。设当前已添加了柱体 0,1,…,t0, 1, \dots, t0,1,…,t(t≥0t \ge 0t≥0),则对于所有可能的支撑层 s=1,2,…,ts = 1, 2, \dots, ts=1,2,…,t,需要检查子塔 s…ts \dots ts…t 是否稳定地放置在柱体 s−1s-1s−1 上。注意:
- 当 t=0t = 0t=0 时,只有柱体 000 放在地面上,地面视为无穷大半径,故永远稳定。
- 当 t≥1t \ge 1t≥1 时,必须检查所有 sss。
一旦发现某个 sss 不满足条件,则塔在添加柱体 ttt 后倒塌,输出 ttt 即可。
复杂度分析
朴素做法:每添加一个柱体 ttt,对 sss 从 111 到 ttt 检查一次稳定性,每次检查需要计算 Xs,tX_{s,t}Xs,t 和 Ys,tY_{s,t}Ys,t。若直接求和,时间复杂度为 O(N3)O(N^3)O(N3),不可接受。
优化:预处理前缀和。
令:
Wi=∑p=0i−1wp,Xi=∑p=0i−1wp⋅xp,Yi=∑p=0i−1wp⋅yp
W_i = \sum_{p=0}^{i-1} w_p,\quad
X_i = \sum_{p=0}^{i-1} w_p \cdot x_p,\quad
Y_i = \sum_{p=0}^{i-1} w_p \cdot y_p
Wi=p=0∑i−1wp,Xi=p=0∑i−1wp⋅xp,Yi=p=0∑i−1wp⋅yp
则:
∑p=stwp=Wt+1−Ws,∑p=stwpxp=Xt+1−Xs,∑p=stwpyp=Yt+1−Ys
\sum_{p=s}^{t} w_p = W_{t+1} - W_s,\quad
\sum_{p=s}^{t} w_p x_p = X_{t+1} - X_s,\quad
\sum_{p=s}^{t} w_p y_p = Y_{t+1} - Y_s
p=s∑twp=Wt+1−Ws,p=s∑twpxp=Xt+1−Xs,p=s∑twpyp=Yt+1−Ys
这样每次检查可在 O(1)O(1)O(1) 时间内计算出子系统的总重量和加权坐标和。总时间复杂度为 O(N2)O(N^2)O(N2),对于 N≤1000N \le 1000N≤1000 完全可行。
精度处理
直接使用整数运算比较 (ΔX)2+(ΔY)2(\Delta X)^2 + (\Delta Y)^2(ΔX)2+(ΔY)2 与 r2⋅(∑w)2r^2 \cdot (\sum w)^2r2⋅(∑w)2 可能产生溢出:
- wi=ri2≤1010w_i = r_i^2 \le 10^{10}wi=ri2≤1010
- 累计 Wt+1≤1000×1010=1013W_{t+1} \le 1000 \times 10^{10} = 10^{13}Wt+1≤1000×1010=1013
- W2≤1026W^2 \le 10^{26}W2≤1026 远超
long long范围(约 9×10189 \times 10^{18}9×1018)
因此,必须使用高精度或浮点数比较。由于题目允许浮点误差且 NNN 不大,使用 long double 计算质心坐标并直接比较距离平方与 r2r^2r2 是安全的,边界判断时加上微小容差。
解题步骤
- 循环读入 NNN,若 N=0N = 0N=0 则结束。
- 存储所有柱体的 (xk,yk,rk)(x_k, y_k, r_k)(xk,yk,rk)。
- 初始化前缀和数组 WWW,XXX,YYY,长度为 N+1N+1N+1,全部置 000。
- 对于 t=0t = 0t=0 到 N−1N-1N−1:
- 计算 wt=rt2w_t = r_t^2wt=rt2。
- 更新前缀和:W[t+1]=W[t]+wtW[t+1] = W[t] + w_tW[t+1]=W[t]+wt,X[t+1]=X[t]+wt⋅xtX[t+1] = X[t] + w_t \cdot x_tX[t+1]=X[t]+wt⋅xt,Y[t+1]=Y[t]+wt⋅ytY[t+1] = Y[t] + w_t \cdot y_tY[t+1]=Y[t]+wt⋅yt。
- 若 t=0t = 0t=0,直接继续下一轮(地面稳定)。
- 否则,对于 s=1s = 1s=1 到 ttt:
- 子系统和:subW=W[t+1]−W[s]subW = W[t+1] - W[s]subW=W[t+1]−W[s],subX=X[t+1]−X[s]subX = X[t+1] - X[s]subX=X[t+1]−X[s],subY=Y[t+1]−Y[s]subY = Y[t+1] - Y[s]subY=Y[t+1]−Y[s]。
- 计算子系统质心:cx=subX/subWcx = subX / subWcx=subX/subW,cy=subY/subWcy = subY / subWcy=subY/subW。
- 计算质心到支撑面圆心的距离平方:dist2=(cx−xs−1)2+(cy−ys−1)2dist2 = (cx - x_{s-1})^2 + (cy - y_{s-1})^2dist2=(cx−xs−1)2+(cy−ys−1)2。
- 若 dist2≥rs−12−ϵdist2 \ge r_{s-1}^2 - \epsilondist2≥rs−12−ϵ,则不稳定,记录 collapseIdx=tcollapseIdx = tcollapseIdx=t 并跳出循环。
- 若发现不稳定,跳出外层循环。
- 根据 feasiblefeasiblefeasible 标志输出结果。
代码实现
// Babel Towers
// UVa ID: 11116
// Verdict: Accepted
// Submission Date: 2026-04-26
// UVa Run Time: 0.000s
//
// 版权所有(C)2026,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
struct Block {
long long x, y, r;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
while (cin >> N, N) {
vector<Block> blocks(N);
for (int i = 0; i < N; ++i)
cin >> blocks[i].x >> blocks[i].y >> blocks[i].r;
vector<long long> cumW(N + 1, 0);
vector<long long> cumX(N + 1, 0);
vector<long long> cumY(N + 1, 0);
bool feasible = true;
int collapseIdx = -1;
for (int t = 0; t < N; ++t) {
long long w = (long long)blocks[t].r * blocks[t].r;
cumW[t + 1] = cumW[t] + w;
cumX[t + 1] = cumX[t] + w * blocks[t].x;
cumY[t + 1] = cumY[t] + w * blocks[t].y;
for (int s = 1; s <= t; ++s) {
long long subW = cumW[t + 1] - cumW[s];
long long subX = cumX[t + 1] - cumX[s];
long long subY = cumY[t + 1] - cumY[s];
// 使用 long double 避免溢出
long double cx = (long double)subX / subW;
long double cy = (long double)subY / subW;
long double dx = cx - blocks[s - 1].x;
long double dy = cy - blocks[s - 1].y;
long double dist2 = dx * dx + dy * dy;
// 边界视为不稳定,加上微小容差
if (dist2 >= (long double)blocks[s - 1].r * blocks[s - 1].r - 1e-12) {
feasible = false;
collapseIdx = t;
break;
}
}
if (!feasible) break;
}
if (feasible) cout << "Feasible\n";
else cout << "Unfeasible " << collapseIdx << "\n";
}
return 0;
}
总结
本题的核心在于正确理解堆叠圆盘的稳定性物理模型,并将其转化为质心与支撑圆盘的几何约束。通过前缀和优化将 O(N3)O(N^3)O(N3) 的朴素算法降为 O(N2)O(N^2)O(N2),同时利用 long double 处理数值溢出问题。注意边界条件(圆盘边缘视为不稳定)以及浮点比较时的容差处理,即可通过在线评测。

3020

被折叠的 条评论
为什么被折叠?



