2024牛客多校第九场

牛客第九场反思

K. kill The Monsters

题意概述

  1. 个怪兽,每个怪兽血量为
  2. 有两种操作:
    • 使得所以的怪兽的血量减少1
    • 使得某一个怪兽得血量变成
    • 是给定的
  3. 问最少操作次数

思路

  1. 最主要的问题就是到底使用哪一种操作
  2. 可以这样想:让某一头怪兽成为基准,大于这个基准的进行操作二变得小于等于这个基准,然后结果就是次数加上基准的血量。这样尽可能的让每一次操作贡献最大
  3. 那么让哪一个成为基准呢?肯定是让结果最小的那个成为基准
  4. 首先肯定能求出来一个最大次数,这个是我们能够接受的上限
  5. 可以尝试让每一个成为基准看哪一个会使得结果最小
  6. 很难算好像,但是如果基准在最前面就好了
  7. 我们可以将所有的数存到一个优先队列里面
  8. 从最大的开始,那么结果就是它的血量
  9. 然后让最大的数去除以, 如果它比老二小,老二就成为了老大,可以变成了新的基准
  10. 如果老大还是老大,重复上面的步骤
  11. 这样每个数成为基准时,大于它的数小于等于它的次数就算出来了

代码

#include <bits/stdc++.h>
//#define int long long
#define pair std::pair<int,int>
#define endl '\n'
using lli = long long;
using ull = unsigned long long;

int nums[100010] = {0};
std::priority_queue<pair> que;
void solve()
{
    int n = 0, k = 0;
    std::cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        std::cin >> nums[i];
        que.emplace(nums[i], i);
    }
    if (k == 1)
    {
        std::cout << que.top().first << endl;
        return;
    }
    int maxn = que.top().first;
    int tmp = 0;
    while(maxn)
    {
        maxn /= k;
        tmp++;
    }
    int cntmaxn = n * tmp;
    int cnt = 0, ans = cntmaxn;
    while(cnt <= cntmaxn && !que.empty())
    {
        pair t = que.top();
        que.pop();
        int tmpres = std::max(t.first / k, que.top().first) + (++cnt);
        ans = std::min(tmpres, ans);
        que.emplace(t.first / k, t.second);
    }
    std::cout << ans << endl;
    
}

signed main()
{
    solve();
    return 0;
}

I. Interesting Numbers

题意概述

  1. 给定一个数
  2. 给一个范围
  3. 求在这个范围中的数中,左右两半都是完全平方数的数有几个

思路

  1. 左右两边看成独立的两个部分
  2. 统计这个部分到9999999...这个数能有几个完全平方数,最后相乘就是一个数能产生的个数
  3. L,R都这样算
  4. 答案就是用L产生的个数减去R产生的个数

代码

#include <bits/stdc++.h>
typedef __int128 i128;
using lli = long long int;
inline void read(i128 &n, std::string s)
{
    int sz = s.size();
    for (int i = 0; i < sz; i++)
    {
        n = n * 10 + s[i] - '0';
    }
}

inline void print(i128 n)
{
    if (n > 9)
    {
        print(n / 10);
    }
    putchar(n % 10 + '0');
}

i128 st = 1, up = 0;
i128 leftfind(i128 x) // 找的的mid mid * mid <= x
{
    i128 l = 0, r = 1e15;
    i128 mid = 0;
    while(l + 1 < r)
    {
        mid = (l + r) / 2;
        if (mid * mid <= x)
        {
            l = mid;
        }
        else
        {
            r = mid;
        }
    }
    return l;
}

i128 rightfind(i128 x) // 找的的mid mid * mid >= x
{
    i128 l = 0, r = 1e15;
    i128 mid = 0;
    while(l + 1 < r)
    {
        mid = (l + r) / 2;
        if (mid * mid < x)
        {
            l = mid;
        }
        else
        {
            r = mid;
        }
    }
    return r;
}

i128 process(std::string s, std::string t)
{
    i128 nums = 0, numt = 0;
    read(nums, s); read(numt, t);
    i128 x = rightfind(nums), y = rightfind(numt);
    if (x * x > nums) return (up - x + 1) * (up + 1);
    return (up - x) * (up + 1) + (up - y + 1);
}

signed main()
{
    int n = 0;
    std::cin >> n;
    for (int i = 1; i <= n / 2; i++)
    {
        st *= 10;
        //print(st);
        //std::cout << '\n';
    }
    st -= 1;
    // print(st);
    // std::cout << '\n';
    up = leftfind(st);
    // print(up);
    // std::cout << '\n';
    std::string l, r;
    std::cin >> l >> r;
    std::string l1 = l.substr(0, n / 2), l2 = l.substr(n / 2, n / 2);
    std::string r1 = r.substr(0, n / 2), r2 = r.substr(n / 2, n / 2);
    // i128 num = 0;
    // read(num, l1);
    // lli x = rightfind(num);
    // std::cout << x;
    i128 cnt1 = process(l1, l2);
    i128 cnt2 = process(r1, r2);
    // print(cnt1);
    // std::cout << '\n';
    // print(cnt2);
    // std::cout << '\n';
    i128 res = cnt1 - cnt2;
    if (n == 2 && r == "99") res++;
    print(res);
    return 0;
}
全部评论

相关推荐

12-09 16:31
已编辑
门头沟学院 前端工程师
Apries:这个阶段来说,很厉害很厉害了,不过写的简历确实不是很行,优势删掉吧,其他的还行
点赞 评论 收藏
分享
求个公司要我:接好运
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务