2024牛客暑假训练营4 (A C F G H I J 题) 代码易看,新手友好✨✨✨

2024牛客暑假训练营4 (A C F G H I J 题) ✨✨✨



A 题 (难度: ✨✨✨)

题目:
详细题目: A题

分析:

代码:

在这里插入代码片

C 题 (难度: ✨)

题目: 从序列最多拿出四个数交换位置,最后按照升序排列,问最少操作次数
详细题目: C题

分析:
通过举例我们大概可以发现,选 4 4 4 个数字按照最优次数交换时,每次都可以将 3 3 3 ~ 4 4 4 个数字放置在正确位置,这个数量取决于圈的大小,如果圈大小为 2 2 2 就先记录下来,凑够两对一起交换,当圈的大小为 3 3 3 或者 4 4 4 时一次就可以换好,

如果大于 4 4 4 那么一次就只能交换 3 3 3 个,这里情况复杂一点
如果圈大小为 6 6 6,交换情况为 3-3 结论 => 当 (edge % 3 3 3 == 0 0 0) 次数为 (edge / 3 3 3)
如果圈大小为 7 7 7,交换情况为 3-4 结论 => 当 (edge % 3 3 3 == 1 1 1) 次数为 (edge / 3 3 3)
如果圈大小为 8 8 8,交换情况为 3-3-2 结论 => 当 (edge % 3 3 3 == 2 2 2) 次数为 (edge / 3 3 3),然后记录最后剩下两个数字情况次数,凑够两对一起交换。

代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 6;
int arr[N];
int vis[N];
int n;

void solve(const int &Case)
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> arr[i];
        vis[i] = 0;
    }

    int ans = 0, e = 0;	// e -> 可以两两交换配对
    for (int i = 1; i <= n; ++i)
    {
        if (vis[i] || i == arr[i]) // 被用或者下标正确
            continue;

        int idx = i, val = 0, cnt = 0;
        while (val != i) // 组圈
        {
            val = arr[idx];
            idx = val;
            vis[idx] = 1;
            cnt++;
        }

        if (cnt == 3 || cnt == 4)
            ans++;
        else
        {
            ans += cnt / 3;
            if (cnt % 3 == 2)
                e++;
        }
    }
    ans += (e + 1) / 2;	// 向上取整
    cout << ans << '\n';
    return;
}

int main(void)
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
        solve(T);
    return 0;
}

F 题


G 题 (签到题)

题目: 将军马饮水问题的变种
已知将军的马在点 ( x G , y G ) \textstyle (x_G, y_G) (xG,yG) 处,帐篷在点 ( x T , y T ) \textstyle (x_T, y_T) (xT,yT) 处,河流位于 x 轴的正半轴和 y 轴的正半轴上,求马从河边喝水返回帐篷所需的最短距离。
详细题目: G题

代码:

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

void solve(const int &Case)
{
    ll xg, yg, xt, yt;
    cin >> xg >> yg >> xt >> yt;
    double res1 = sqrt((xt - xg) * (xt - xg) + (yt + yg) * (yt + yg));
    double res2 = sqrt((xt + xg) * (xt + xg) + (yt - yg) * (yt - yg));
    double res = min(res1, res2);
    cout << fixed << setprecision(10) << res << '\n';
    return;
}

int main(void)
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
        solve(T);
    return 0;
}

H 题 (难度: ✨✨)

题目: H题

分析:
如果你举例推导就大概会发现这样的 规律:
1.如果数字都一样,输出 0 (包括 n==1 时)
2.如果差值有倍数关系,比如差值为(2,6,8)以及(4,6,12)时候输出 2,但是差值为(4,8,12)的时候输出 4
3.其他时候都输出 1
最后得出 结论:
这个题重点在看 各项之间的差值 有什么关系
不难发现,最后输出结果为 差值的gcd

小技巧
这里不需要特判序列数字是否一样,总长度是否为1,不需要数字一样时跳过,也不需要初始化d=arr[n]-arr[1]然后对每次gdc(d,arr[i]-arr[i-1])取最小值(想不明白看看gcd板子思考一下)
放一下gcd板子

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

代码:

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 1e5 + 5;
ll arr[N];

void solve(const int &Case)
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> arr[i];
    sort(arr + 1, arr + n + 1);

    ll d = 0;
    for (int i = 2; i <= n; ++i)
        d = gcd(d, arr[i] - arr[i - 1]);
        
    cout << d << '\n';
    return;
}

int main(void)
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
        solve(T);
    return 0;
}

I 题 (难度: ✨)

题目: n \textstyle n n 个人站成一排,从左到右依次为 1 \textstyle 1 1 n \textstyle n n。这些人中,有 m \textstyle m m对朋友。
当且仅当区间内的每一对人都是朋友时,定义区间 [ l , r ] \textstyle [l,r] [l,r] 1 ≤ l ≤ r ≤ n \textstyle 1 \leq l \leq r \leq n 1lrn)为友好区间,有多少友好区间?

详细题目: I题

分析:
这个题就是使用双指针确定区间位置,对区间右边的人(未加入)进行判断,每当有新人加入增加区间数量即可

代码:

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

const int N = 1e6 + 6;
vector<vector<int>> arr(N);

int n, m;

int main(void)
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m;

    int u, v;
    while (m--)
    {
        cin >> u >> v;
        arr[u].push_back(v);
    }
    
    ll ans = n;
    int l = 1, r = 1;
    while (r <= n)
    {
        int flag = 1;
        for (int i = l; i <= r; ++i)
        {
            if (arr[i].size() == 0 || count(arr[i].begin(), arr[i].end(), r + 1) == 0)
            {
                flag = 0;
                break;
            }
        }
        if (flag)
        {
            r += 1;
            ans += r - l;
        }
        else
        {
            l += 1;
            r = max(r, l);
        }
    }
    cout << ans << '\n';
    return 0;
}

J 题


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值