日常训练2025-1-21

日常训练2025-1-21

E双生双宿之错

rating:1300

https://ac.nowcoder.com/acm/contest/95323/E

思路(数论)

本题考查中位数定理,中位数有这样的性质 :所有数与中位数的绝对差之和最小。中位数是数列中间的那个数,或者是中间的那两个数之一。

所以最后得到的双生数组中的两种数即为数列左半截的中位数,和右半截的中位数。当左右的中位数相同时,让其中一个 +1 或者 -1,特判一下即可

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; i++){
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
int h = n / 2;
int ml = a[h / 2], mr = a[h + h / 2];
i64 ans = INF;
for (auto x : {ml, ml - 1}){
for (auto y : {mr, mr + 1}){
if (x == y) continue;
i64 res = 0;
for (int i = 0; i < h; i++){
res += abs(a[i] - x);
}
for (int i = h; i < n; i++){
res += abs(a[i] - y);
}
ans = std::min(ans, res);
}
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
std::cin >> t;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

J硝基甲苯之袭

rating:1500

https://ac.nowcoder.com/acm/contest/95323/J

思路(优化枚举)

本题考点在于如何利用题目给的信息中隐藏的性质优化枚举。

暴力枚举每一个数,O(n2),显然不可行。但是考虑到 如果 i<j ,则 gcd(i,j) 一定为 i 的因子,设此因子为 g 则公式化为 i ^ j == g。g的范围小了很多,我们能否通过枚举 i 和 g 间接得到 j 呢,显然是可以的。j = i ^ g,此时我们已经验证了 i ^ j == g 的,还需要验证 gcd(i,j)==g,只要满足我们就统计答案。

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; i++) std::cin >> a[i];
int maxx = *std::max_element(a.begin(), a.end());
std::vector<int> cnt(maxx+1);
for (int i = 0; i < n; i++){
cnt[a[i]] += 1;
}
i64 ans = 0;
for (int g = 1; g <= maxx; g++){
for (int i = g; i <= maxx; i += g){
int j = i ^ g;
if (i < j && std::gcd(i, j) == g && j <= maxx){
ans += 1LL * cnt[i] * cnt[j];
}
}
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

井然有序之窗

rating:1600

https://ac.nowcoder.com/acm/contest/95323/H

思路(贪心)

我们先将所有区间排序,用一个优先队列来维护“可选的区间右端点”。当我们指定某个区间为ii的时候,我们首先将所有以ii为左端点的区间加入优先队列,然后尽量选择目前最小的那个右端点即可。

代码

#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using u128 = unsigned __int128;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> l(n), r(n);
std::vector<int> p(n);
std::vector<std::vector<int>> vec(n); // vec[i]:表示左端的为 i 的点的集合
for (int i = 0; i < n; i++) {
std::cin >> l[i] >> r[i];
l[i]--;
vec[l[i]].push_back(i);
}
std::priority_queue<std::array<int, 2>, std::vector<std::array<int, 2>>, std::greater<>> pq;
for (int x = 0; x < n; x++) {
for (auto i : vec[x]) {
pq.push({r[i], i});
}
if (pq.empty()) {
std::cout << -1 << "\n";
return 0;
}
auto [r, i] = pq.top();
pq.pop();
if (x >= r) {
std::cout << -1 << "\n";
return 0;
}
p[i] = x;
}
for (int i = 0; i < n; i++) {
std::cout << p[i] + 1 << " \n"[i == n - 1];
}
return 0;
}

M数值膨胀之美

rating:1400

https://ac.nowcoder.com/acm/contest/95323/M

思路(模拟+贪心)

让包含初始最小值的区间逐渐向左右两边扩展,让每一个数都有一次乘2,且统计答案的机会。

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
std::multiset<i64> s;
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
s.insert(a[i]);
}
i64 ans = 1e18;
for (int i = 0; i < n; ++ i) {
if (a[i] == *s.begin()) {
s.extract(a[i]);
s.insert(a[i] * 2);
ans = std::min(ans, *s.rbegin() - *s.begin());
int l = i - 1, r = i + 1;
while (l >= 0 || r < n) {
if ( r >= n || (a[l] == *s.begin() && l >= 0)) {
s.extract(a[l]);
s.insert(a[l] * 2);
ans = std::min(ans, *s.rbegin() - *s.begin());
-- l;
} else{
s.extract(a[r]);
s.insert(a[r] * 2);
ans = std::min(ans, *s.rbegin() - *s.begin());
++ r;
}
}
break;
}
}
std::cout << ans << "\n";
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

本文作者:califeee

本文链接:https://www.cnblogs.com/califeee/p/18684510

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   califeee  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.