2 条题解

  • 0
    @ 2026-4-23 23:59:31

    想法肯定是,去贪。

    经过基础的调整后,容易发现:最优状态下,一定有任何两条连线都相交(视作圆内部的连线)。

    考虑枚举(固定)最短的线段,发现问题转化为求一张二分图的最大匹配。

    发现每个左部点对应右部点的一个区间,且区间的左右端点都有单调性。那直接贪心就是对的,复杂度 O(N3)O(N^3)

    图示:

    深蓝色为固定的线段,浅蓝色圆弧为红色点可以匹配的区间。

    参考代码:

    #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
      @ 2026-3-3 8:38:17

      (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 1kN/21 \leqslant k \leqslant \lfloor N/2 \rfloor.

      Observation: For each K, there is an optimal set of chords such that every pair of distinct chords intersect.

      Proof: Consider any four endpoints p1,p2,p3,p4p_1, p_2, p_3, p_4 on the circle 0p1<p2<p3<p4<C0 \leqslant p_1 < p_2 < p_3 < p_4 < C.

      Suppose WLOG that the two non-intersecting chords are (p1,p2)(p_1, p_2) and (p3,p4)(p_3, p_4). 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 (p1,p3)(p_1, p_3) and (p2,p4)(p_2, p_4). 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 σnewσold\sigma_{\text{new}} \geqslant \sigma_{\text{old}}. 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 C(p3p1)C - (p_3 - p_1).

      Case 1: p3p1C/2p_3 - p_1 \leqslant C/2.

      $$C - (p_3 - p_1) \geqslant p_3 - p_1 > p_2 - p_1 \geqslant \sigma_{\text{old}}.$$

      Case 2: p3p1>C/2p_3 - p_1 > C/2.

      C(p3p1)<p3p1,C - (p_3 - p_1) < p_3 - p_1, $$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 C(p4p2)C - (p_4 - p_2), hence no new smaller value is introduced by replacing the chords (p1,p2)(p_1, p_2) and (p3,p4)(p_3, p_4) with (p1,p3)(p_1, p_3) and (p2,p4)(p_2, p_4).

      Notice now, that for an arbitrary arrangement of k>1k > 1 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 (p1,p2)(p_1, p_2) must now intersect with either (p1,p3)(p_1, p_3), or (p2,p4)(p_2, p_4), 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 K1K - 1 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 N(N1)/2N(N - 1)/2 pairs of endpoints (i,j)(i, j). Let the distance of the chord from ii to jj be d=min(LiLj,CLiLj)d = \min(|L_i - L_j|, C - |L_i - L_j|). Then, we move two pointers starting from ii and jj in the same direction around the circle, adding chords when possible. In particular, when we encounter endpoints (i,j)(i', j'), let $d' = \min(|L_{i'} - L_{j'}|, C - |L_{i'} - L_{j'}|)$.

      Let the positive distance from ii' to jj' be dp=(LjLi)d_p = (L_{j'} - L_{i'}) if i<ji' < j', and dp=C(LiLj)d_p = C - (L_{i'} - L_{j'}) otherwise.

      Case 1: dp=d<dd_p = d' < d. Increment jj'.

      Case 2: Cdp=d<dC - d_p = d' < d. Increment ii'.

      Case 3: ddd' \geqslant d. Add the chord (i,j)(i', j') to the construction. Increment both ii and jj.

      Notice that in the first two cases, we advance the pointer that may potentially increase dd'.

      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 N(N1)/2N(N - 1)/2 pairs of possible minimal distances and kept track of the maximal kk achievable, we will have for every kk also found the maximal minimum distance.

      The time complexity is O(N3)O(N^3), 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 O(N2)O(N^2)!

      • 1

      信息

      ID
      2264
      时间
      2000ms
      内存
      256MiB
      难度
      10
      标签
      递交数
      2
      已通过
      1
      上传者