当前位置: 首页 > news >正文

The 2022 ICPC Asia Xian Regional Contest(E,L)题解

E

Find Maximum

题意:

首先,通过观察与打表,可以发现:

规律
对于非负整数 x,函数 f(x) 的值等于:
将 xx 写成三进制后,各个位数的数字之和 + 该三进制数的位数

例如,

  • x=1002(3),则有 f(1002(3))=(1+0+0+2)+4=7。


最大化策略:

由于 f(x) 的值为「位数之和 + 位数」,为了尽可能让 f(x)最大,我们需要:

  • 尽可能多地让每个位为数字 2,因为 2 是三进制单个位的最大贡献。

因此问题转化为:

如何在给定区间 [l,r] 中,找到一个三进制表示的数字,使它尽可能地填满数字 2?


具体策略分析:

分情况讨论:

① 若 l 与 r 位数相同:

这种情况下,我们从高位往低位遍历

  • 找到从最高位开始第一个 r与 l 不相同的位。

  • 将这一位上的数字(对应的是 r 上的数字)减去 1(此处保证减1后仍然大于或等于 l)。

  • 将减1之后的这一位后面的所有位(低位)全部填充为数字 2

可以证明这是最佳策略,举个具体例子:

  • 假设给定 l=120000, r=130000:

    • 三进制表示:

      • l=01112120002(3)

      • r=11222012102(3)

    • 第一个不同位是最高位的 1 与 0 的位置。
      我们对 r 的最高位 1 进行减1操作,使其变为 0

    • 此时前面所有的低位均可填充数字 2,于是我们选出数字:22222222002

    • 对应的 f(x)为各位数字之和(2×8+0+0+2=18)+ 位数(11)=29,是最大值。


② 若 r 位数比 l 多:

在此情况下,我们不一定只是简单地对最高位做减1操作,原因是:

  • 如果 r 的最高位本身是 1,减1后变成 0,最高位少了一个 2 的贡献,反而降低了总贡献。

  • 这种时候应该对 从最高位到最低的每个比 l 多出来的位数分别做一次减1操作,并将低位填满数字 2,逐个进行判断并取最大值。

举例说明:

  • 假设 l=1,r=15(10)=120(3)

    • 最高位直接减1为:220,贡献为 (2+2+0)+3=7。

    • 若不小心减去最高位变为 0,比如变为 021,贡献仅为 (0+2+1)+3=6,反而更小。

  • 因此,对于这种情况需要逐个测试所有可能的位置(多出来的位),并选最大值。


③ 特殊情况(l=r):

  • 如果 l=r,则答案直接为 f(l)。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
#define pii pair<int, int>
#define lowbit(x) (x & (-x))
int f(int x)
{if (x == 0)return 1;if (x > 0 && x % 3 == 0)return f(x / 3) + 1;if (x > 0 && x % 3 != 0)return f(x - 1) + 1;
}
vector<int> get(int x)
{vector<int> v;while (x){v.push_back(x % 3);x /= 3;}return v;
}
int l, r;
void solve()
{cin >> l >> r;vector<int> v1 = get(l);vector<int> v2 = get(r);if (v2.size() > v1.size()){int res = 3 * (v2.size() - 1) + (v2.back() - 1) + (v2.back() != 1);res = max(res, f(r));int sum = v2.back() + 1;for (int i = v2.size() - 2; i >= max((int)v1.size() - 1ll, 1ll); i--){if (v2[i] >= 1)res = max(res, sum + i * 3 + v2[i]);}cout << res << endl;return;}int res = 0;for (int i = v2.size() - 1; i >= 0; i--){if (v2[i] == v1[i])res += v2[i] + 1;else{res += 3 * i + v2[i];break;}}res = max(res, f(r));cout << res << endl;
}
signed main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;cin >> t;while (t--)solve();
}
L

Tree

题意:

怎么操作

  • 反链(条件2)操作
    我们希望每次将最多的节点放入一个集合中。显然,将当前树中所有叶子节点组成一个集合,是最优的做法。

  • 链状(条件1)操作
    依然选择所有的叶子节点,每个叶子节点往上会形成一个链,我们可以选这些链进行1操作。

综上所述:

  • 反链(条件2)操作,每次只需增加1个集合(所有叶子同时处理)。
  • 链状(条件1)操作,每个叶子节点都要单独形成一个集合(增加集合数等于当前叶子节点个数)。

因此,从全局最优的角度看,明显条件2(反链)是我们更倾向于多次重复的操作,而条件1(链状)适合最后进行一次收尾。

基于以上的分析,我们确定最佳策略:

  • 从树的叶子节点开始,每次进行一次**反链(条件2)**操作(将所有当前叶子放入同一个集合)。
  • 每次执行完反链操作后,将这些叶子节点删除,得到一个更小的树,再次重复上述步骤。
  • 在任意一次反链操作结束后,我们都可以选择结束此过程,转而执行一次链状(条件1)操作来处理当前树剩余的所有叶子节点。

换句话说,整个过程是:

  • 反复地进行条件2操作(每次集合数+1);
  • 在任何时刻可以决定不再进行条件2,改用条件1进行一次性收尾(集合数增加当前树中剩余叶子节点个数);
  • 我们尝试所有可能的停止时刻,取其中的最小值即可。

从叶子节点开始跑拓扑排序即可

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
#define pii pair<int, int>
#define lowbit(x) (x & (-x))
void solve()
{int n;cin >> n;vector<int> in(n + 10, 0);vector<int> fa(n + 10, 0);in[0] = 1e9;for (int i = 2; i <= n; i++){int x;cin >> x;fa[i] = x, in[x]++;}queue<int> q;for (int i = 2; i <= n; i++)if (in[i] == 0)q.push(i);int cnt = 0;int res = n;while (!q.empty()){res = min(res, cnt + (int)q.size());cnt++;int sz = q.size();while (sz--){int t = q.front();q.pop();int x = fa[t];in[x]--;if (in[x] == 0)q.push(x);}}cout << res << endl;
}
signed main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;cin >> t;while (t--)solve();
}

相关文章:

  • 鸿蒙:DevEco Studio配置ohpm时,cmd正常,在终端出现‘ohpm‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
  • PHP 编程:现代 Web 开发的基石与演进
  • Vue.js 组件开发指南
  • vim启动的时候,执行gg
  • (3)python开发经验
  • c#中equal方法与gethashcode方法之间有何关联?
  • Linux514 rsync 解决方案环境配置
  • MySQL之基础事务
  • Python uv包管理器使用指南:从入门到精通
  • 鸿蒙5.0项目开发——鸿蒙天气项目的实现(主页1)
  • 力扣144题:二叉树的前序遍历(递归)
  • 力扣-105.从前序与中序遍历序列构造二叉树
  • 国产ETL数据集成软件和Informatica 相比如何
  • Node.js中MongoDB连接的进阶模块化封装
  • attention_weights = torch.ones_like(prompt_embedding[:, :, 0]):切片操作获取第二维度,第三维度
  • OpenCV人脸识别LBPH算法原理、案例解析
  • BGP联邦和发射试验
  • 查询公网IP地址的方法:查看自己是不是公网ip,附内网穿透外网域名访问方案
  • python如何合并excel单元格
  • 生成式AI辅助编程目录
  • 北方产粮大省遭遇气象干旱,夏粮用水如何解决?
  • 沧州低空经济起飞:飞行汽车开启千亿赛道,通用机场布局文旅体验
  • 鄂州交警通报致1死2伤车祸:女子操作不当引发,已被刑拘
  • 昆明警方重拳打击经济领域违法犯罪:去年抓获905名嫌犯
  • 2025财政观察|长三角“三公”经费普降,钱要用在刀刃上
  • 学习教育期间违规吃喝,李献林、叶金广等人被通报