牛客编程巅峰赛S1第3场 - 青铜&白银 -题解

牛客编程巅峰赛S1第3场 - 青铜&白银

A-[位数求和]

思路:

直接按照枚举\([10^n,10^{n+1}-1]\)种的每个数,$O(log_{10}(x))判断每位上的数字之和为m即可。

代码:
class Solution {
public:
    /**
     * 返回这样的数之和
     * @param n int整型 数的长度
     * @param m int整型 各个为之和
     * @return long长整型
     */
    long long sum(int n, int m) {
        // write code here
       int base = 1;
        for (int i = 1; i <= n - 1; ++i)
        {
            base *= 10;
        }
        int up = base * 10 - 1;
        long long ans = 0;
        for (int i = base; i <= up; ++i)
        {
            int num = i;
            int cnt = 0;
            while (num > 0)
            {
                cnt += num % 10;
                num /= 10;
            }
            if (cnt == m)
            {
                ans += i;
            }
        }
        return ans;
    }
};

B-不可思议

思路:

仔细观察生成的树的随机代码:

seed4 = (seed1 + seed2) % 998244353 * seed3 % 998244353;
        u[i] = i + 1;
        v[i] = (seed4 % i) + 1;

每一个边都是一个新节点和之前已经出现的节点连边。

这样生成的树高度的期望值是\(O(log_2(n))\),所以先预处理每一个节点的父节点后,

对于每一个询问可以直接暴力求即可。

代码:
class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param seed1 long长整型 
     * @param seed2 long长整型 
     * @param seed3 long长整型 
     * @param x int整型 
     * @return long长整型
     */
    int u[100010], v[100010];
std::vector<int> e[100010];
void get_tree(long long seed1 , long long seed2, long long seed3, int n)
{
    long long seed4;
    for (int i = 1; i <= n - 1; ++i)
    {
        seed4 = (seed1 + seed2) % 998244353 * seed3 % 998244353;
        u[i] = i + 1;
        v[i] = (seed4 % i) + 1;
        seed3 = seed2;
        seed2 = seed1;
        seed1 = seed4;
    }
}
int far[100010];
void dfs(int x, int pre)
{
    far[x] = pre;
    for (auto &y : e[x])
    {
        if (y != pre)
        {
            dfs(y, x);
        }
    }

}
int ans(int x, int y)
{
    int res = 0;
    while (1)
    {
        res += ((y + 2 * x) ^ (y + x));
        if (x == 1)
        {
            break;
        } else
        {
            x = far[x];
        }
    }
    return res;
}
long long work(int n, long long seed1, long long seed2, long long seed3, int x) {
    // write code here
    get_tree(seed1,  seed2,  seed3, n);
    for (int i = 1; i < n; ++i)
    {
        e[v[i]].push_back(u[i]);
        e[u[i]].push_back(v[i]);
    }
    dfs(1, 0);
    int lastans = 0;
    int ret = 0;
    int y = 0;
    int z;
    for (int i = 1; i <= n; ++i)
    {
        z = ans(x, y);
        ret = (ret + z) % 998244353;
        lastans = z;
        x = ((x + lastans)^ret) % n + 1;
        y = lastans;
    }
    return ret;
}
};

C-牛牛晾衣服

思路:

二分\(mid\)代表要多少时间可以把衣服全烘干,显然具有单调性(\(mid\)可以烘干的话,\(mid+1\)一定可以。)

然后对于每一个衣服\(a_i\),找到最小的\(x\)使其\(a_i-x*k-(mid-x)<=0\),然后如果可以找到且\(x\in[0,mid]\),以及\(\mathit x\)的总和\(sum\le mid\)

代码:
class Solution {
public:
    int C(int x, int y)
    {
        return (x + y - 1) / y;
    }
    bool check(int mid,  vector<int>& a, int k)
    {
        int n = a.size();
        int cnt = 0;
        if (mid >= a[0])
            return 1;
        for (int i = 0; i < n; ++i)
        {
            if (mid * k < a[i])
                return 0;

            int x = C(max(a[i] - mid, 0), k - 1);
            if (x < 0 || x > mid)
            {
                return 0;
            }
            cnt += x;
        }
        return cnt <= mid;
    }
    int solve(int n, vector<int>& a, int k) {
        // write code here
        sort(a.begin(), a.end(), greater<int>());
        int l = 1;
        int r = 1000000000;
        int mid;
        int ans ;
        while (l <= r)
        {
            mid = (l + r) >> 1;
            if (check(mid, a, k))
            {
                ans = mid;
                r = mid - 1;
            } else
            {
                l = mid + 1;
            }
        }
        return ans;
    }
};
posted @ 2020-07-16 22:47  茄子Min  阅读(180)  评论(0编辑  收藏  举报