ZROJ3265 猜数游戏

显示器上有五个数位,每个位置可以显示 \(0\)\(9\),也就是说显示器可以显示 \(0\)\(99999\) 的所有数。

初始所有位置都是 \(0\)。给定 \(L,R\),系统将从 \([L,R]\) 中随机选出一个数字 \(x\),我们的目标是猜出这个数。

每一秒,我们可以干两件事情中的一件:

  • 将显示器上的某一个数位上的数字修改为任意数字。
  • 询问当前数字和 \(x\) 的大小关系(返回大于,等于或小于)。

你需要求出,在最劣情况下,我们最少需要几秒可以确定出一个唯一的 \(x\)

\(1 \le n \le 10^5\),最多 \(50\) 次多测,\(8\) 秒。


一开始一直想着直接构造,结果直接炸了。()

我们考虑 \(O(n^3)\) 的区间 dp。

我们发现每一次的转移点要么在当前区间的左边,否则右边。

那么我们设 \(f(l,r,0/1)\),表示确定答案在 \([l,r]\) 范围内,当前显示屏上的数字在 \(l-1/r+1\) 的位置。

不难发现转移封闭,那么我们就成功拿到了 \(40\) 的暴力分。


考虑优化,我们发现这道题答案值域极其小(\(\le 5\log n\)),打表甚至可以发现答案 \(\le 42\)

因此考虑把这个作为 dp 对象。我们设 \(g(x,k,0/1)\),表示 \(x\) 作为 左/右 端点时最靠 右/左 的答案 \(\le k\) 的另外一个端点。

考虑转移,以 \(g({x,k,0})\) 为例。

相当于找到一个点 \(p\) 作为下一个切割的点,满足 \(g({p-1,k-1-d(x,p),1})\le x\),贡献就是 \(g({p+1,k-1-d(x,p),0})\)

这里 \(d(x,y)\) 表示在显示器上把 \(x\) 改为 \(y\) 的最小操作次数。

做到这一点后我们从小到大枚举 \(k\),那么就可以在 \(\mathcal O(n^2\log n)\) 解决。


考虑继续优化,我们发现阻挡我们进一步优化的瓶颈在于 \(d\) 函数无法优美地表示。

加入一个巧妙的转化,我们发现这个相当于我们可以选择将 \(x,y\) 的每一位改成 \(-1\),然后最小的能够使得 \(x\)\(y\) 完全相同的修改次数就是 \(d(x,y)\) 的两倍。

这个形式特别像高位前缀和,考虑将原本的数看作 1\(-1\) 看作 0,那么贡献与求和的形式其实就是高位前缀与后缀和。

这样我们就可以以 \(2^5\) 的单次代价暴力往上加 \(d\) 的贡献,保存到一个 \(11^5\) 的桶中,\(10^5\) 这个数可能需要单独处理。

那么接下来我们扫描线,在每个位置上维护可以转化到他的数(高位后缀和),查询的时候暴力遍历。

这一部分可以在 \(42*32*n=1344n\) 的时间内解决。


最后是查询,由于第一次分割比较特殊,我们考虑枚举第一次的切割点,然后二分答案。

那么可以简单地在 \(O(Tn\log\log n)\) 的时间内完成。

至此就解决了这道问题。


后记:

如果答案值域小,可以考虑把答案作为 dp 限制,原限制作为 dp 对象。

posted @ 2025-08-06 20:04  CuteNess  阅读(18)  评论(0)    收藏  举报