2024 ICPC ShaanXi Provincial Contest E.Trade Road

题目链接:商路

首先需要发现一些性质:假设存在一条合法商路\overrightarrow{AB},设C、D为圆上不同于A、B的两点,\overrightarrow{CD}之间不可能建立一条合法商路。

题解里面给了很详细的证明The 2024 ICPC ShaanXi Provincial Contest,这里不过多解释。

通过这个性质,自己画几个图就可以发现,最终的连成的图会是一个菊花图(都和同一个点相连),或者存在一个等腰三角形也是合法的。

先不考虑连成三角形的特殊情况,既然最后连成的图是一个菊花图,那么那么我们统计每个点的度数,最后的答案就是度数的最大值。我们用双指针遍历每一个点(因为距离先增大后减小),维护每一个点能构建的商路。我们发现连完之后是会存在两条商路相交的,但是我们要的是某一个点的度数,仔细观察我们构建的商路,可以发现对于每一个点,只保留该点上的商路就能做到所有的商路不相交,该点上的商路数量也就是该点的度数。

再对特殊的连成三角形的情况进行考虑。有可能存在一个等腰三角形是很好想到的,那我们再想想除了这个等腰三角形之外,要是还存在一个其他的点,那么可能出现以下两种情况:

  1. 距离顶点最远的点不再是原本三角形中的另外两个点。
  2. 距离非顶点最远的点不再是顶点。

(图画的不是很好,图中的AB应该是和AC长度相等的)图中D点对应情况1,如果点D存在,那么距离顶点A最远的点应该是点D而不是B和C,所以商路最终无法连成三角形;图中E点对应情况2,如果点E存在,那么距离非顶点B最远的点不再是顶点A,所以商路最终也无法连成三角形。

这两种情况都会导致最终无法连成三角形,那么能够连成三角形的情况只能是刚好由三个点构成一个等腰三角形,而构成三角形的情况正好比一般情况推出的答案多一,直接特判就行。

#include <bits/stdc++.h>
#define fixed(s) fixed<<setprecision(12)<<s

using namespace std;
typedef long long ll;
typedef array<int, 3> Arr;
typedef pair<int, int> PII;

const int N = 2e5 + 7;

int k, n;
int a[N], d[N];
int dist[N];

int dis(int u, int v){ //计算两点距离
    u = a[u], v = a[v];
    if (u > v) swap(u, v);
    return min(v - u, u + k - v);
}

void solve(){
    cin >> k >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1, j = 1; i <= n; i++){
        while (dis(i, j) <= dis(i, j % n + 1)){
            //如果点i到点j的距离和距离点j最远的点的距离不相等,说明本该建商路的i和j之间还没有建成商路
            if (dis(i, j) == dis(i, j % n + 1) && dis(i, j) != dist[j]){
                //构建商路
                ++d[i], ++d[j];
            }
            j = j % n + 1;
        }
        //更新距离点i最远的距离
        dist[i] = dis(i, j);
        //和上面构建商路的道理相同
        if (dist[i] != dist[j]) ++d[i], ++d[j];
    }
    bool ok = false;
    //特判三角形的情况
    if (n == 3){
        int res[3] = {a[2] - a[1], a[3] - a[2], a[1] + k - a[3]};
        sort(res, res + 3);
        ok = (res[0] == res[1]);
    }
    cout << *max_element(d + 1, d + n + 1) + ok;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T = 1;
    //cin >> T;
    while(T--){
        solve();
    }
    return 0;
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值