专栏文章
题解:P12976 受力分析 Force
P12976题解参与者 1已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mip0qsti
- 此快照首次捕获于
- 2025/12/03 04:16 3 个月前
- 此快照最后确认于
- 2025/12/03 04:16 3 个月前
赛时被硬控 2h 然后有一个处理(新建
dis 为 的辅助点)没想到,喜提 30 pts。做法好像和官解不太一样……?
我们直入主题吧。
,考虑先固定 ,那么 的取值范围就是一系列平移之后的线段的交。
字典序要求先让 尽可能小,所以考虑什么时候有解。考虑怎么处理 个线段有交,猜当且仅当两两线段有交。(oi 为什么需要证明?猜就完事了! 证明见文末。)
那么考虑两条线段有交的问题。对于同一个 有 ,两条线段有交那么 即 ,整理就是 的形式。这是什么?差分约束!贺个板子先。 建图,spfa 最坏复杂度 ,基本没问题。
仔细一想,差分约束求出的就是天然最大解(不等式 很多都取等了),但我们需要最小解,好办!, 最大解就是 最小解了。然后把 带回原式可以得到 的取值范围,最小值就出来了。
你说的对,但是需要 怎么办?一开始容易想到平移(所有 加一个数,所有 减这个数,解仍然合法),然后一交只有 30pts。事实上考虑比如最小解 不合法,如果 合法,你对最小解直接平移变成 就不是最优解了。怎么办呢?注(看)意(题)到(解)!,那么新建一个点令其
dis 为 然后建边权为 的边就好了。你说的对,但是需要 怎么办?我还是采用平移的方法,但事后发现根本不会出现 的情况。事实上(感谢出题人 Comentropy),如果存在 那么 (因为 ),也就是说 内没有 ,那么可以进行如下的调整:将所有 减小 同时将所有 增大 ,调整后的解一定合法,与调整前解字典序最小矛盾。所以直接求出的 一定非负。
下面是我的实现:(完整代码见 R221749640)
CPP// 注意 dis 要开 long long 不然负环走几圈早爆 int 了
#define rep(i, x, y) for(auto i = (x); i <= (y); i++)
int l[N][N], r[N][N];
int ans1[N], ans2[N];//即题目中的 x, y
int main() {
scanf("%d", &n);
rep(i, 1, n) rep(j, 1, n) scanf("%d", l[i] + j);
rep(i, 1, n) rep(j, 1, n) scanf("%d", r[i] + j);
rep(i, 1, n) rep(j, 1, n) if(i != j) {//此处 j 即为题解中 i', k 为题解中 j
// xi - xj >= l(i,k) - r(j,k), (-xj) - (-xi) >= ~
int p = -(1 << 30);
rep(k, 1, n) p = max(p, l[i][k] - r[j][k]);
//b - a >= x, a <= b - x, dis(i) <= dis(j) + (-x)
add(j, i, -p);
}
rep(i, 1, n) add(n + 1, i, 0); //dis(u) <= dis(n + 1) ( = 0) + w (= 0)
SPFA(n + 1);//dis(n+1) 天然为 0
if(negative_loop) return puts("-1"), 0;//不要忘了main返回值是0!
rep(i, 1, n) ans1[i] = -dis[i];
int mn = *std::min_element(ans1 + 1, ans1 + n + 1);//注意不要写成 min(int*, int*),后者在对指针取min(
rep(i, 1, n) ans1[i] -= mn;//平移,使最小值为 0,防止求出 (1,1) 这种解
rep(j, 1, n) {
ans2[j] = -(1 << 30);
rep(i, 1, n) ans2[j] = max(ans2[j], l[i][j] - ans1[i]);
}
assert(*std::min_element(ans2 + 1, ans2 + n + 1) >= 0);//proved.
rangewriteln(ans1 + 1, ans1 + n + 1);
rangewriteln(ans2 + 1, ans2 + n + 1);
return 0;
}
撒花!
另外提供一个自造样例:
CPP2
2 4
1 5
3 6
2 7
题面样例改了一个数,输出和题面样例一致。应该能很搞出一些错吧。
对于“ 个线段有交当且仅当两两线段有交”的证明:充分性显,考虑必要性(如果 个线段两两有交,那么这些线段就有交吗?)。注意到 条线段的交就是 ,如果 条线段没有交那么一定存在一个 比另一个 大,那么这两条线段就没有交,必要性得证。事实上推广到集合就不成立了(比如 )。
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...