首页 > 其他分享 >P10218-魔法手杖

P10218-魔法手杖

时间:2024-07-26 18:29:11浏览次数:10  
标签:P10218 int LL 魔法 mnv read 手杖 lev ans

题面

\(O(nk^2)\)

我们考虑如果确定了 \(ans\),如何判断是否合法?

考虑从高到低逐位确定 \(x\)。

设 \(ans\) 和 \(x\) 的第 \(i\) 位为 \(ans_i,x_i\)。

分类讨论一波:

如果 \(ans_i\) 为:

  • 0:无论 \(x_i\) 取什么,总有一边在异或 \(x\) 后第 \(i\) 位为 1。

    • \(x_i=0\),那么右子树一定比 \(ans\) 大。所以向左子树递归。
    • \(x_i=1\),同理,向右子树递归。
  • 1:无论 \(x_i\) 取什么,总有一边在异或 \(x\) 后第 \(i\) 位为 0,小于答案。所以一定有一颗子树全部使用加法。

    • \(x_i=0\),那么左子树在只使用异或时一定比 \(ans\) 小。所以左子树全部使用加法。向右子树递归。
    • \(x_i=1\),同理,向左子树递归。

注意到当 \(ans_i=1\) 时一颗子树就算全部加法也不一定安稳,仍有可能小于 \(ans\)。

所以需要给 \(x\) 限制最小值 \(mnx\),表示应当有求出的 \(x\geq mnx\)。

因为用加法的每个数加上 \(x\) 都应当 \(\geq ans\)。所以当 \(ans_i=1\) 时可以用 (\(ans\ -\) 加法子树内 \(a\) 的最小值) 更新 \(mnx\)。

如果搜到第 \(i\) 位时 \(x+2^i-1<mnx\),这个分支就没救了,直接返回。

如果有搜到最后的,说明 \(ans\) 可能。二分即可。

单次判断 \(O(nk)\),二分 \(O(k)\)。总复杂度 \(O(nk^2)\)。

\(O(nk)\)

线段树上二分可以去掉一只 \(\log\),Trie 树上二分是不是可以去掉一个 \(k\)?

考虑逐位确定 \(ans\)。

注意到一个性质,如果 \(ans\) 开始确定第 \(i\) 位,如果接下来 \(i\) 位的确定方式中有一种可行,那么低 \(i\) 位全部置 0(设为 \(ans0\))也一定可行。

所以当前分支可能当且仅当接下来 \(i\) 位都为 0 也可能。

这是容易的。

设当前已经确定的 \(x\) 为 \(x0\)。

因为当前子树去掉低 \(i\) 位都和 \(ans0\) 相等,所以只要考虑加法子树。

设加法子树的最小值为 \(mnv\),那么 \(x\geq ans0-mnv\)。

因为 \(x\leq x0+2^{i+1}-1\),所以有解当且仅当 \(sumcost<m\) 并且 \(ans0-mnv< 2^{i+1}+x0\)。

所以只要维护 \(sumcost,x,ans,mnv\) 即可。

特判一下如果到了空子树,那么答案直接是 \(\min(ans + 2^{i+1} - 1, mnv + x + 2^{i+1} - 1)\),就是 \(mnv\) 可以够到的最大值。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

using LL = __int128;

namespace fastio {
const int mxn = 1 << 22;
char buf[mxn], *S = NULL, *T = NULL;
inline char Getchar(){return (S == T ? T = (S = buf) + fread(buf, 1, mxn, stdin) : 0, S == T ? EOF : *S++);}
template <typename T> void read(T &x)
{
    x = 0; char c = 0;
    for(c = Getchar(); c != EOF && (c < '0' || c > '9'); c = Getchar());
    while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = Getchar();
}
template <typename T, typename... _T> void read(T &x, _T&... y){read(x);read(y...);}
void write(LL x)
{
    if(x > 9)write(x / 10);
	putchar(x % 10 + '0');
}
inline void printLL(LL x) {write(x); putchar('\n');}
}
using fastio::read, fastio::printLL;

const int N = 1e5 + 5, K = 120, W = 7;
int n, m, k;
LL a[N], mn[N << W], val[N << W];
int b[N], sc[N << W];

int s[N << W][2], idx;

inline int nw(int &x) {return x ? x : x = ++idx;}

void ins(int x, int lev, LL v, int cost)
{
    while(lev >= -1)
    {
        mn[x] = min(mn[x], v ^ ((v >> lev + 1) << lev + 1));
        val[x] = min(val[x], v);
        sc[x] = min((int)(1e9 + 5), sc[x] + cost);
        x = nw(s[x][(v >> lev) & 1]);
        if(lev < 0) val[x] = v;
        lev --;
    }
}

void init()
{
    memset(mn, 0x3e, sizeof(mn[0]) * ((n * k) + 5));
    memset(val, 0x3e, sizeof(val[0]) * ((n * k) + 5));
    memset(sc, 0, sizeof(sc[0]) * ((n * k) + 5));
    memset(s, 0, sizeof(s[0][0]) * ((n * k * 2) + 10));
    idx = 1;
}

LL ans;
bool dfs(int x, int lev, int nc, LL now, LL mnv, LL nowans)
{
    const LL v1 = (LL)1 << lev, v2 = (LL)1 << lev + 1;
    if(nc > m || nowans > mnv + now + v2 - 1) return 0;
    if(lev == -1 || !x) return ans = max(ans, min(nowans + v2 - 1, mnv + now + v2 - 1)), 1;
    int cnt = 0;
    // 右侧 + -> x = 1
    if(nc + sc[s[x][1]] <= m) cnt += dfs(s[x][0], lev - 1, nc + sc[s[x][1]], now + v1, min(mnv, val[s[x][1]]), nowans + v1);
    // 左侧 + -> x = 0
    if(nc + sc[s[x][0]] <= m) cnt += dfs(s[x][1], lev - 1, nc + sc[s[x][0]], now, min(mnv, val[s[x][0]]), nowans + v1);
    if(!cnt)
    {
        // 右侧 ok -> x = 0
        dfs(s[x][0], lev - 1, nc, now, mnv, nowans);
        // 左侧 ok -> x = 1
        dfs(s[x][1], lev - 1, nc, now + v1, mnv, nowans);
    }
    return 1;
}

void solve()
{
    read(n, m, k);
    init();
    k --;
    for(int i = 1; i <= n; i ++) read(a[i]);
    ll sum = 0;
    for(int i = 1; i <= n; i ++) read(b[i]), sum += b[i];
    if(sum <= m)
    {
        LL ans = (LL)1 << (k + 3);
        for(int i = 1; i <= n; i ++) ans = min(ans, a[i]);
        printLL(ans + ((LL)1 << k + 1) - 1);
        return;
    }
    for(int i = 1; i <= n; i ++)
        ins(1, k, a[i], b[i]);
    ans = 0;
    dfs(1, k, 0, 0, (LL)1 << 123, 0);
    printLL(ans);
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int c, t; read(c, t);
    while(t --) solve();

    return 0;
}

标签:P10218,int,LL,魔法,mnv,read,手杖,lev,ans
From: https://www.cnblogs.com/adam01/p/18326009

相关文章

  • 牛可乐与魔法封印----(二分)
     题目描述牛可乐得到了一个长度为n且非严格单调递增的序列 a,然而这个序列被q层魔法封印了,其中第i 层封印的问题包含两个整数xi,yi(xi≤yi),牛可乐必须正确回答序列中大于等于xi且小于等于yi​的数字个数才能够解开该层封印。牛可乐觉得这个问题太难了,于是他想请......
  • Lottie:动态动画的魔法棒
    文章目录引言官网链接Lottie的原理基础使用1.导出动画2.引入Lottie库3.加载和播放动画高级使用1.动画控制2.交互性3.自定义动画例子:交互式按钮动画优缺点优点缺点结语引言Lottie是Airbnb开源的一个动画库,它允许设计师在AdobeAfterEffects中创建......
  • 数据增强:机器学习中的数据魔法
    数据增强:机器学习中的数据魔法在机器学习领域,数据是模型训练的基石。然而,获取大量高质量的训练数据往往是一个挑战。数据增强技术应运而生,它通过从现有数据中生成新的变体来增加数据集的多样性和丰富性。本文将深入探讨数据增强的概念、重要性以及如何在实践中应用数据增强......
  • 博文标题:探索Python中的元编程:装饰器的魔法
    引言在Python的世界里,装饰器(Decorators)是一种非常强大的特性,它允许程序员在不修改原始函数代码的情况下,为函数添加新的功能。这种机制不仅增强了代码的可读性和可维护性,还提供了高度的灵活性和扩展性。本文将深入探讨装饰器的基本概念、工作原理以及如何利用它们来简化和......
  • 揭秘@Autowired:手把手教你复刻Spring依赖注入魔法
    文章目录手写一个@Autowired注解实现自动注入@Autowired注解的作用@Autowired的实现原理手写一个@MyAutowired注解定义@MyAutowired注解创建注解处理器集成自定义处理器总结@Autowired主要功能@Autowired实现原理手写@MyAutowired注解注意事项手写一个@Autowir......
  • C++宏魔法:__VA_OPT__操作
    在阅读chromium源码的时候,在\blinkrendercore的base\check.h头文件中,发现了这个定义:#defineCHECK(condition,...)\LOGGING_CHECK_FUNCTION_IMPL(\::logging::C......
  • Python与OpenCV的魔法:批量将照片变身为精美素描图
    1.前言在数字图像处理领域,图像转换和滤波是非常常见的操作。特别是将彩色照片转换为素描图,这种技术可以用于艺术创作、图像分析以及一些特殊的图像处理需求。本文将详细介绍如何使用Python和OpenCV库批量将任意图片转换为素描图。2.简介OpenCV(OpenSourceComputerVisionL......
  • C语言函数:编程世界的魔法钥匙(1)
    目录1.C语言中的函数是什么?2.函数的分类:2.1标准库函数2.1.1库函数的诞生:2.1.2库函数的作用:2.1.3如何学习使用库函数2.2自定义函数2.2.1函数的组成:2.2.2自定义函数的优点  2.2.3 例题3.函数的参数3.1实际参数(实参):3.2形式参数(形参):4.函数的调用4.1......
  • 表格集算表高性能原理:揭秘纯前端百万行数据秒级响应的魔法
    最新技术资源(建议收藏)https://www.grapecity.com.cn/resources/集算表(TableSheet)是一个具备高性能渲染、数据绑定功能、公式计算能力的数据表格,通过全新构建的关系型数据管理器结合结构化公式,在高性能表格的基础上提供排序、筛选、样式、行列冻结、自动更新、单元格更新等功......
  • Laravel数据库的魔法棒:深入探索数据库迁移(Migrations)
    Laravel数据库的魔法棒:深入探索数据库迁移(Migrations)在Laravel的世界中,数据库迁移(Migrations)是一种强大的工具,它允许开发者以版本控制的方式管理数据库结构的变化。通过迁移,你可以轻松地创建、修改或删除数据库表,同时保持代码的整洁和一致性。本文将带你深入了解Laravel数......