【CF】Day66——Edu 168.D + CF 853 (Div. 2).C (树 + 二分 + 贪心 | 组合数学)

D. Maximize the Root

题目:

思路:

树上二分,中下题

我们可以发现如果 x 可以,那么 x - 1 肯定也可以,所以可以直接二分答案

具体的,我们每次二分能增加的值 mid ,如果 a[i] < mid,那么子树就要 a[i] + a[i] - mid 个,否则直接递归子树即可,以此类推,具体实现看代码

代码:

cpp 复制代码
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"

void solve()
{
    int n;
    cin >> n;
    vector<int> a(n + 1);
    vector<vector<int>> g(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 2; i <= n; i++)
    {
        int p; cin >> p;
        g[p].push_back(i);
    }
    if (n == 1)
    {
        cout << a[1] << endl;
        return;
    }
    auto check = [&](int need) ->bool{
        int flag = 1;
        auto dfs = [&](auto self,int fa,int needval) ->void{
            if (!flag)
            {
                return;
            }
            if (fa != 1)
                needval += max(needval - a[fa], 0LL);
            if (needval > a[fa] && g[fa].empty() || needval > 1e9)
            {
                flag = 0;
                return;
            }
            for (auto& son : g[fa])
            {
                self(self, son, needval);
            }
            };
        dfs(dfs, 1, need);
        return flag;
        };
    int l = 0, r = 1e9;
    while (l + 1 < r)
    {
        int mid = l + r >> 1;
        if (check(mid))
        {
            l = mid;
        }
        else
        {
            r = mid;
        }
    }
    if (check(r))
    {
        cout << a[1] + r << endl;
        return;
    }
    cout << a[1] + l << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C. Serval and Toxel's Arrays

题目:

思路:

很考验实现方式的一题

遇到这种题,我们要知道拆分,即把每个数的奉献算出来再累加即可

对于一个数 x,如果 我们选了一个 没有 x 的数组,那么奉献就是 1,取有 x 的数列,奉献也是 1,但是这是两种不同的取法,所以我们可以分开计算(特别的一共有 m + 1个数组,因为还有初始数组)

对于第一种取法,那么就是 cnt += xhas * (m + 1 - xhas),其中 xhas 为 x 的数量

对于第二种取法,有 cnt += xhas * (xhas-1) / 2

由于 n + m 不是很大,所以枚举 n+m 的每一个数是可行的,那么如何快速计算 xhas 成了问题

我们可以这样想,由于每次只改变一个数,那么也就是说如果某个数一直没改变,那么最后肯定有 m + 1 个,而如果中间改变过,那么肯定在改变之前这个数就一直存在了,也就是连续的某一段全含有 x,所以我们可以存储 last[i] 代表上一个数是否存在,以及如果存在它的位置在哪里

这样我们就解决了 xhas 的问题,具体实现看代码

代码:

cpp 复制代码
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"

void solve()
{
    int n, m;
    cin >> n >> m;
    vector<int> a(n+1),last(n+m+1,-1),cnt(n+m+1,0);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        last[a[i]] = 0;
    }
    for (int i = 1; i <= m; i++)
    {
        int p, v;
        cin >> p >> v;
        if (a[p] != v)
        {
            cnt[a[p]] += i - last[a[p]];
            last[a[p]] = -1;
            last[v] = i;
            a[p] = v;
        }
    }
    int res = 0;
    for (int i = 1;i <= n+m;i++)
    {
        if (last[i] != -1)
        {
            cnt[i] += m - last[i] + 1;
        }
    }
    for (int i = 1; i <= n + m; i++)
    {
        res += cnt[i] * (m + 1 - cnt[i]);
        res += cnt[i] * (cnt[i] - 1) / 2;
    }
    cout << res << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}
相关推荐
啟明起鸣29 分钟前
【数据结构】B 树——高度近似可”独木成林“的榕树——详细解说与其 C 代码实现
c语言·开发语言·数据结构
lxmyzzs1 小时前
【图像算法 - 23】工业应用:基于深度学习YOLO12与OpenCV的仪器仪表智能识别系统
人工智能·深度学习·opencv·算法·计算机视觉·图像算法·仪器仪表识别
Learn Beyond Limits1 小时前
Multi-output Classification and Multi-label Classification|多输出分类和多标签分类
人工智能·深度学习·神经网络·算法·机器学习·分类·吴恩达
张较瘦_1 小时前
[论文阅读] 软件工程 | GPS算法:用“路径摘要”当向导,软件模型检测从此告别“瞎找bug”
论文阅读·算法·bug
XH华1 小时前
C语言第十三章自定义类型:联合和枚举
c语言·开发语言
2401_858286112 小时前
OS26.【Linux】进程程序替换(下)
linux·运维·服务器·开发语言·算法·exec·进程
草莓熊Lotso2 小时前
【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day13
c语言·开发语言·刷题·强化训练
张同学的IT技术日记2 小时前
【奇妙的数据结构世界】用图像和代码对队列的使用进行透彻学习 | C++
算法
极客BIM工作室2 小时前
强化学习算法分类与介绍(含权重更新公式)
算法·分类·数据挖掘
KarrySmile2 小时前
Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
数据结构·算法·链表·双指针·快慢指针·hot100·灵艾山茶府