2 条题解
-
0
想法肯定是,去贪。
经过基础的调整后,容易发现:最优状态下,一定有任何两条连线都相交(视作圆内部的连线)。
考虑枚举(固定)最短的线段,发现问题转化为求一张二分图的最大匹配。
发现每个左部点对应右部点的一个区间,且区间的左右端点都有单调性。那直接贪心就是对的,复杂度 。
图示:

深蓝色为固定的线段,浅蓝色圆弧为红色点可以匹配的区间。
参考代码:
#include<bits/stdc++.h> #define ffor(i,a,b) for(int i=(a);i<=(b);i++) #define roff(i,a,b) for(int i=(a);i>=(b);i--) using namespace std; const int MAXN=2000+10; int n,c,l[MAXN],ans[MAXN]; int calc_dis(int u,int v) { if(u>n) u-=n; if(v>n) v-=n; int dis=abs(l[u]-l[v]); return min(dis,c-dis); } int calc(int x,int y) { int L=y+1,R=x+n-1,ans=1,lim=calc_dis(x,y); ffor(i,x+1,y-1) if(L<=R) { if(L<=R&&calc_dis(i,L)<lim) while(L<R&&calc_dis(i,L)<lim&&calc_dis(i,L+1)>calc_dis(i,L)) L++; if(L<=R&&calc_dis(i,L)>=lim) ans++,L++; } return ans; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>n>>c; ffor(i,1,n) cin>>l[i],l[i+n]=l[i]+c; ffor(i,1,n) ffor(j,i+1,n) { int v=calc(i,j); ans[v]=max(ans[v],calc_dis(i,j)); } roff(i,n/2,1) ans[i]=max(ans[i+1],ans[i]); ffor(i,1,n/2) cout<<ans[i]<<' '; return 0; } -
0
(Analysis by Botao Yuan)
Given N distinct points along a circle, select k distinct chords such that the minimum distance between the endpoints of any chord along the circumference of the circle is maximized. Chords cannot share endpoints. We need to determine the maximal minimum distance for all .
Observation: For each K, there is an optimal set of chords such that every pair of distinct chords intersect.
Proof: Consider any four endpoints on the circle .
Suppose WLOG that the two non-intersecting chords are and . The minimum circular distance among their endpoints is
$$\sigma_{\text{old}} = \min(p_2 - p_1, C - (p_2 - p_1), p_4 - p_3, C - (p_4 - p_3)).$$Now swap the endpoints so that the chords intersect. The new chords must be and . The minimum circular distance in the new configuration is
$$\sigma_{\text{new}} = \min(p_3 - p_1, C - (p_3 - p_1), p_4 - p_2, C - (p_4 - p_2)).$$We show that . Clearly,
$$p_3 - p_1 > p_2 - p_1 \geqslant \sigma_{\text{old}}, \quad p_4 - p_2 > p_4 - p_3 \geqslant \sigma_{\text{old}}.$$It remains to consider the complementary arc .
Case 1: .
$$C - (p_3 - p_1) \geqslant p_3 - p_1 > p_2 - p_1 \geqslant \sigma_{\text{old}}.$$Case 2: .
$$C - (p_3 - p_1) = (C - (p_4 - p_1)) + (p_4 - p_3) \geqslant p_4 - p_3 \geqslant \sigma_{\text{old}}.$$The same argument applies for , hence no new smaller value is introduced by replacing the chords and with and .
Notice now, that for an arbitrary arrangement of chords, if we rearrange the endpoints of two non-intersecting chords such that they now intersect, the total number of pairs of intersecting chords always increases. Clearly, we will increment this value when we introduce the new pair. However, casework analysis can show that any arbitrary chord which once intersected with must now intersect with either , or , thus we do not lose any intersections. Hence by the exchange argument, any optimal solution can eventually be transformed into one in which every pair of chords intersects.
Observe now that in such an optimal construction, the chord endpoints alternate around the circle; as we traverse the circle, we encounter exactly one endpoint of each chord before seeing its other endpoint. Thus, for a fixed chord, we can find the maximum K such that there are other chords with distance greater than or equal to it by greedily adding chords while going around the circle.
To be more specific, we will iterate over all pairs of endpoints . Let the distance of the chord from to be . Then, we move two pointers starting from and in the same direction around the circle, adding chords when possible. In particular, when we encounter endpoints , let $d' = \min(|L_{i'} - L_{j'}|, C - |L_{i'} - L_{j'}|)$.
Let the positive distance from to be if , and otherwise.
Case 1: . Increment .
Case 2: . Increment .
Case 3: . Add the chord to the construction. Increment both and .
Notice that in the first two cases, we advance the pointer that may potentially increase .
The greedy construction can be proven to achieve the maximum number of chords with a fixed chord of minimal distance, also using an exchange argument.
Since we have exhausted all pairs of possible minimal distances and kept track of the maximal achievable, we will have for every also found the maximal minimum distance.
The time complexity is , but the constant factor is quite good.
Example implementation:
#include <bits/stdc++.h> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(0); int N, C; cin >> N >> C; vector<int> L(N); for (auto & x: L) { cin >> x; } vector<int> ans(N / 2 + 1); for (int i = 0; i < N; ++i) { for (int j = i + 1; j < N; ++j) { int i2 = (i + 1) % N, j2 = (j + 1) % N; int min_dist = min(L.at(j) - L.at(i), C - (L.at(j) - L.at(i))); int cnt = 1; while (i2 != j && j2 != i) { // distance from L[i2] to L[j2] in the positive direction int cur_dist = i2 < j2 ? L.at(j2) - L.at(i2) : C - (L.at(i2) - L.at(j2)); if (cur_dist < min_dist) { j2 = (j2 + 1 == N ? 0 : j2 + 1); } else if (C - cur_dist < min_dist) { i2 = (i2 + 1 == N ? 0 : i2 + 1); } else { cnt++; i2 = (i2 + 1 == N ? 0 : i2 + 1); j2 = (j2 + 1 == N ? 0 : j2 + 1); } } ans.at(cnt) = max(ans.at(cnt), min_dist); } } ans.erase(ans.begin()); for (int i = (int)ans.size() - 2; i >= 0; --i) { ans.at(i) = max(ans.at(i), ans.at(i + 1)); } for (int i = 0; i < N / 2; ++i) { cout << ans[i] << " \n"[i + 1 == N / 2]; } }Bonus: solve in !
- 1
信息
- ID
- 2264
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者