AtCoder Beginner Contest 281 (E-F)

22 篇文章 1 订阅
21 篇文章 0 订阅

E - Least Elements (atcoder.jp)

        (1)题目大意

                给你一个长度为N的序列A,并且两个整数M和K,连续M个里面前K小的数的和。

         (2)解题思路

                考虑用multiset进行模拟,定义两个multiset,mt1表示维护前k个最小的,mt2表示剩下的m-k个,然后用个s维护mt1里面的数的和,每次pop掉一个下标下雨i-m的数。

        (3)代码实现

#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
ll a[N];
void solve()
{
    multiset<ll> mt1, mt2;
    ll s = 0;
    int n, m, k;
    cin >> n >> m >> k;
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, m) mt1.insert(a[i]), s += a[i];
    while (mt1.size() > k)
    {
        ll v = *(--mt1.end());
        mt1.erase((--mt1.end()));
        s -= v;
        mt2.insert(v);
    }
    vector<ll> ans;
    ans.push_back(s);
    rep(i, m + 1, n)
    {
        ll last = *(--mt1.end());
        if (a[i] > last)
            mt2.insert(a[i]);
        else
            mt1.insert(a[i]), s += a[i];
        if (mt1.find(a[i - m]) != mt1.end())
        {
            s -= a[i - m];
            mt1.erase(mt1.find(a[i - m]));
        }
        else
        {
            mt2.erase(mt2.find(a[i - m]));
        }
        while (mt1.size() > k)
        {
            ll v = *--mt1.end();
            mt2.insert(v);
            s -= v;
            // cout << "1:" << i << ',' << v << endl;/
            mt1.erase(--mt1.end());
        }
        while (mt1.size() < k)
        {
            ll v = *(mt2.begin());
            mt1.insert(v);
            s += v;
            // cout << "2:" << i << ',' << v << endl;
            mt2.erase(mt2.begin());
        }
        ans.push_back(s);
    }
    for (auto x : ans)
        cout << x << ' ';
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--)
        solve();
    return 0;
}

F - Xor Minimization (atcoder.jp)
        (1)题目大意

                给你一个长度为N的序列A,让你找出一个x,使得异或每一个A[i]后的M的最大值最小,让你输出这个M是多少。

         (2)解题思路

                考虑字典树预处理出每一个数的30位,然后dfs从最高位开始,若当前位不存在0,那我们往1走,若不存在1,那我们往0走,若两个都存在则我们选择从0走或者从1走取个最小值加上当前1<<f(f表示当前是第几位)就可以。

        (3)代码实现

// Problem: F - Xor Minimization
// Contest: AtCoder - AtCoder Beginner Contest 281
// URL: https://atcoder.jp/contests/abc281/tasks/abc281_f
// Memory Limit: 1024 MB
// Time Limit: 2500 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
int seg[N * 30][2], a[N], idx;
void insert(int x)
{
    int p = 0;
    for (int i = 29; i >= 0; i--)
    {
        int to = x >> i & 1;
        if (!seg[p][to])
        {
            seg[p][to] = ++idx;
        }
        p = seg[p][to];
    }
}
int dfs(int f, int root, int num)
{
    if (f == -1)
    {
        return 0;
    }
    if (!seg[root][1])
    {
        return dfs(f - 1, seg[root][0], num);
    }
    else if (!seg[root][0])
    {
        return dfs(f - 1, seg[root][1], num);
    }
    else
    {
        return (1 << f) + min(dfs(f - 1, seg[root][0], num), dfs(f - 1, seg[root][1], num));
    }
}
void solve()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        insert(a[i]);
    }
    cout << dfs(29, 0, 0) << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--)
        solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值