89 场双周赛

2.二的幂数组中查询范围内的乘积

解法1. 暴力枚举

n最大是1e9,未超出int表示范围,最多有30个2的幂

查询数组最大是1e5

暴力枚举的最差时间复杂度就是3e6,不会超时

时间复杂度

  1. 求2的幂,O(log2n)
  2. m次查询,每次查询最多花费O(log2n),总的时间复杂度

O(log2n+mlog2n) = O(mlog2n)

class Solution {
public:
    vector<int> productQueries(int n, vector<vector<int>>& queries) {
        vector<int> exp;
        int mod = 1e9 + 7;
        for(int i = 1; i <= n; i *= 2)
            if(i & n) exp.push_back(i);

        vector<int> ans;
        for(auto &query : queries)
        {
            long long res = 1;
            while(query[0] <= query[1])
                res = res * exp[query[0]++] % mod; 
            ans.push_back(res);
        }
        return ans;
    }
};

解法2. 暴力枚举 + 预处理

在解法1的基础上,预处理出所有可能的query,之后再查询时,时间复杂度就是O(1)

解法1已知最多有30个2的幂,query可能的选择有30+29+28+....+1=3031/2

时间复杂度

  1. 求2的幂, O(log2n)
  2. 预处理O((log2nlog2n)/2)=O((log22n)/2)
class Solution {
public:
    vector<int> productQueries(int n, vector<vector<int>>& queries) {
        vector<int> exp;
        int mod = 1e9 + 7;
        vector<vector<int>> pre(31, vector<int>(31));
        for(int i = 1; i <= n; i *= 2)
            if(i & n) exp.push_back(i);

        for(int i = 0; i < exp.size(); i++)
        {
            long long base = 1;
            for(int j = i; j < exp.size(); j++)
            {
                base = base * exp[j] % mod;
                pre[i][j] = base;
            }
        }

        vector<int> ans;
        for(auto &query : queries)
            ans.push_back(pre[query[0]][query[1]]);
        return ans;
    }
};

解法3. 幂次的前缀和

  1. 所有的乘子都是2的幂,所以可以转换成求出2的幂次

    比如例1的第三个查询1248=20212223=26

class Solution {
public:
    vector<int> productQueries(int n, vector<vector<int>> queries) {
        vector<int> exp;
        int mod = 1e9 + 7;
        exp.push_back(0);
        for(int i = 1, base = 0; i <= n; i *= 2)
        {
            if(i & n) exp.push_back(base);
            ++base;
        }

        for(int i = 1; i < exp.size(); i++)
            exp[i] += exp[i - 1];

        vector<int> ans;
        for(auto &query : queries)
        {
            int l = query[0] + 1, r = query[1] + 1;
            long long res = 1, tmp = 2;
            for(int pow = exp[r] - exp[l - 1]; pow > 0; pow >>= 1)
            {
                if(pow & 1)  res = (res * tmp) % mod;
                tmp = tmp * tmp % mod;
            }
            ans.push_back(res);
        }
        return ans;
    }
};

3. 最小化数据中的最大值

解法1. 枚举 + 二分

check函数逻辑

根据给出的target值, 从后向前枚举, 设置num[i] <= target ,最后根据nums[0]判断这个target是否满足check要求

时间复杂度

target最大取值为1e9, 二分check用时O(n), 二分用时O(log21e9),总的时间复杂度是

O(30n)

class Solution {
public:
    bool check(vector<int>& nums, int target)
    {
        long long extra = 0;
        for(int i = nums.size() - 1; i >= 1; i--)
            if(extra + nums[i] > target) extra += nums[i] - target;
            else extra = max(0, (int)extra - target - nums[i]);
        return nums[0] + extra <= target;
    }

    int minimizeArrayValue(vector<int>& nums) {
        int l = 0, r = 1e9 + 10, n = nums.size();
        while(l < r)
        {
            int mid = (l + r) >> 1;
            if(check(nums, mid)) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

解法2 求平均数

首先可以明确, 右边的值可以转移到左边任意位置,

可以将初始的nums想象为拥有一个不同浪高的海, 后边的浪可以向前滚动,显然当浪高不同时,会发生流动,当海浪平静, 即浪高相同时就能得到最小的最大浪高,即最小最大值

因此可以从前向后求每一点的平均值,这里的平均值需要向上取整,求val/x,且向上取整的结果是val+(x1)x

class Solution {
public:
    int minimizeArrayValue(vector<int> nums) {
        int ans = 0;
        long long tmp = 0;
        for(int i = 0; i < nums.size(); i++){
            tmp += nums[i];
            ans = max(ans, (int)((tmp + i)/(i + 1)));
        }
        return ans;
    }
};

2440. 创建价值相同的连通块

https://www.bilibili.com/video/BV1cV4y157BY/?vd_source=016995e9e676ce29a2a00ff61948cbc5

const int N = 1e6 + 10;
int h[N], val[N], ne[N], idx;
class Solution {
public:
    int target = 0;
    vector<int> w;

    void add(int a, int b)
    {
        val[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }

    int dfs(int p, int fa)
    {
        int weight = w[p];
        for(int i = h[p]; i != -1; i = ne[i])
        {
            int j = val[i];
            if(j == fa) continue;
            int tmp;
            if((tmp = dfs(j, p)) == -1)
                return -1;
            weight += tmp;
        }
        if(weight > target) return -1;
        if(weight == target) return 0;
        return weight;
    }

    int componentValue(vector<int> nums, vector<vector<int>> edges) {
        memset(h, -1, sizeof h);
        w = nums;
        for(auto &edge: edges)
        {
            int a = edge[0], b = edge[1];
            add(a, b), add(b, a);
        }
        int total = 0;
        for(auto & num : nums)
            total += num;
        for(int i = 1; i <= total; i++)
            if(total % i == 0)
            {
                target = i;
                if(dfs(0, -1) != -1) return total / i - 1;
            }
        return 0;
    }
};
posted @   INnoVation-V2  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示