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 1≤l≤r≤n)为友好区间,有多少友好区间?
详细题目: 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;
}