Codeforces Round #762 (Div.3)

#762(Div.3)

可能是更好的阅读体验

B. Squares and Cubes

题意

给定数字 \(n\) ,求 \(1 \sim n\) 中有多少平方数和立方数。

分析

由于只需要找平方数和立方数,我们可以暴力找出所有平方数和立方数,复杂度为 \(log n\) ,注意判重。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200010;

void solve ()
{
    map<int, bool> ex; // 判重数组
    int n, ans = 0; cin >> n;
    for (int i = 1; i <= n / i; i ++ )
    {
        ans ++ ;
        ex[i * i] = 1;
    }
    for (int i = 1; i * i <= n / i; i ++ )
        if (!ex[i * i * i]) ans ++ ;
    cout << ans << endl;
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--; ) solve();
    return 0;
}

C. Wrong Addition

题意

给定加法法则为:从右到左计算,每次把各位相加的结果填充到结果而不是进位。

即: \(88 + 99 = 1717\)

给出加数、和,求另一个加数。

分析

从加数、和的最后一位开始,如果在当前位,加数小于和,那么一定存在进位,否则一定不存在进位。

不存在解的情况:

  1. 在某一位上,当前加数的位数大于和的位数
  2. 在进位的时候发现和的前一位不是1

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define all(a) begin(a),end(a)
using namespace std;

void solve ()
{
    string a, s, ans; cin >> a >> s;
    for (int p = s.size() - 1, pa = a.size() - 1; p >= 0; )
    {
        // 存在某一位,使得当前加数的数量大于和
        if (pa > p) return cout << -1 << endl, void();
        if (pa < 0) // 加数已经结束了,直接把和加上去
        {
            ans += s[p--];
            continue;
        }
        if (s[p] >= a[pa]) // 不存在进位
        {
            ans += s[p] - a[pa] + '0';
            p -- ; pa -- ;
        }
        else // 存在进位
        {
            // 存在进位,那么和的前一位一定是1
            if (s[p - 1] != '1') return cout << -1 << endl, void();
            ans += s[p] + 10 - a[pa] + '0';
            p -= 2; pa -- ;
        }
    }
    reverse(all(ans));
    while(ans[0] == '0') ans = ans.substr(1);
    cout << ans << endl;
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--; ) solve();
    return 0;
}

D. New Year's Problem

题意

给出矩阵 \(p_{ij}\)\(1 \le i \le m, \ 1 \le j \le n\)

选择至多 \(n-1\) 行,然后在选择的行中,每一列挑选一个数字,求选择的数字的最小值的最大值。

分析

要求最小值的最大值,可以想到用二分答案。

由于要选择至多 \(n-1\) 行,那么我们只需要找出有 \(2\) 个数字在同一行即可。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define int long long
using namespace std;

void solve ()
{
    int n, m; cin >> m >> n;
    vector<vector<int>> p(m, vector<int>(n));
    rep(i, 0, m-1) rep(j, 0, n-1) cin >> p[i][j];

    auto check = [&] (int mid) -> bool
    {
        map<int, bool> ex; // 存储满足的商店
        bool may = 0; // may表示存在两列可以选择同一行
        // 使用may是为了防止后面的列中不存在大于等于mid的数字
        for (int i = 0; i < n; i ++ )
        {
            bool f = 0; // 是否存在至少一个数字满足大于等于mid
            for (int j = 0; j < m; j ++ )
                if (p[j][i] >= mid)
                {
                    if (ex[j]) may = 1;
                    ex[j] = 1; f = 1;
                }
            if (!f) return false;
        }
        return may;
    };

    int l = 1, r = 1e9 + 10;
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << r << endl;
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--; ) solve();
    return 0;
}

E. MEX and increments

题意

给出 \(n\) 个数字,每次操作可以把一个数字加1。可以操作任意次。

问:对于数字 \(i \ (0 \le i \le n)\) ,是否存在一种操作,可以满足序列的 \(mex\)\(i\) 。输出它的最小操作次数。

分析

对于数字 \(i\) ,假设 \(cnt([0, i-1]) < i\) ,那么一定不能把前面 \(i\) 个数字填满,一定无解。

否则,我们可以选择把离它最近的位置,填到 \(i-1\) 的位置,使得序列的 \(mex\)\(i\)

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
using namespace std;
using PII = pair<int, int>;
#define int long long
const int N = 200010;

int cnt[N];

void solve ()
{
    int n; cin >> n;
    vector<PII> mct; // mct 用来动态记录cnt
    for (int i = 0; i <= n; i ++ ) cnt[i] = 0;
    for (int i = 1, x; i <= n && cin >> x; i ++ ) ++ cnt[x];
    int precnt = 0, d = 0;
    // 对于0,特殊判断
    cout << cnt[0] << ' ';
    if (cnt[0] > 1) mct.push_back({0, cnt[0] - 1});
    for (int i = 1; i <= n; i ++ )
    {
        precnt += cnt[i-1];
        if (precnt < i)
        {
            while(i ++ <= n) cout << -1 << " \n" [i - 1 == n];
            return ;
        }
        // 如果i-1的位置没有元素,要把i-1铺掉
        if (!cnt[i-1])
        {
            while (!mct[mct.size() - 1].second) mct.pop_back();
            -- mct[mct.size() - 1].second;
            d += i - 1 - mct[mct.size() - 1].first;
        }
        cout << d + cnt[i] << ' ';
        if (cnt[i] > 1) mct.push_back({i, cnt[i] - 1});
    }
    cout << endl;
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--; ) solve();
    return 0;
}
posted @ 2021-12-21 11:01  Horb7  阅读(253)  评论(1编辑  收藏  举报