日常训练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(n^2)\),显然不可行。但是考虑到 如果 \(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;
}
posted @ 2025-01-21 21:44  califeee  阅读(36)  评论(0)    收藏  举报