P7116 [NOIP2020] 微信步数

原题

简化题意:
有一个 k 维场地,第 i 维宽为 wi,即第 i 维的合法坐标为 1, 2, · · · ,wi。
小 C 有一个长为 n 的行动序列,第 i 元素为二元组 (ci, di),表示这次行动小 C 的坐标由 (x1, x2, . . . , xci, . . . , xk) 变为(x1, x2, . . . , xci + di, . . . , xk)。小 C 会将行动序列重复无限次,直到走出这个场地。
接下来,小 C 会以场地中的每个整点为起点,按照行动序列走直到走出场地。小 C 想知道他一共会走几步。
答案对1e9 + 7取模
\(n <= 5e5, k <= 10, wi <= 1e9, di \in {-1,1}\)

首先因为每一位是独立的,我们不妨把k维拆开

我们可以发现如果枚举每个位置并模拟走路过程复杂度必然爆炸,故此我们考虑改变记录答案的方式

我们考虑对于每个移动次数\(i\)多有少个起点走\(i\)步还没有走出去,如果没有会产生+1的贡献

我们不妨设\(i=k \times n + j\),我们只需要考虑j不同即可,因为在\(i\mod n\)的情况下每个数只有初始位置是不同的

定义\(s_d\)表示走了一个周期(即走了一个循环)后这一维的变化量,\(premax_{i,d}\)表示\(d\)这一维走前\(i\)步时的前缀最小位移,\(premin_{i,d}\)表示\(d\)这一维走前\(i\)时的前缀最大位移

对于从\(x_d\)开始走了\(k\)个完整周期又走了\(i\)步的第\(d\)维,要满足以下条件:

  • \(s_d > 0\),我们可以发现走了\(i\)步后依然没有走出去的条件要求:

    1. \(x_d + premin_{n,d} \geq 1\),意思是这个点的坐标在第一周期任何一步都>= 1,而又因为\(s_d>0\),所以在任意时间都>=1
    2. \(x_d + s_d \times k + premax_{i,d} \leq w_i\),意思是这个点的坐标在最后一个周期后走的\(i\)步内\(\leq w_i\)
    3. \(x_d + s_d \times (k-1) + premax_{n,d} \leq w_i\),意思是这个点坐标在最后一个周期走完后位置\(\leq w_i\),而又因为\(s_d>0\),所以在任意时间都\(\leq w_i\)
    • 合并后即为\(1 - premax_{n,d} \leq x_d \leq w_i - s_d \times k - \max(premax_{i,d},premax_{n,d}-s_d)\)
  • \(s_d < 0\)时,相同的,可以得到:\(1 - s_d \times k - \min(premin_{i,d}, premin_{n,d} - s_d) \leq x_d \leq w_i - premax_{n,d}\)

  • 对于\(s_d = 0\),可以得到:\(1 - premin_{n,d} \leq x_d \leq w_i - premax_{n,d}\)

我们可以发现我们在计算时已经枚举了\(i\), \(d\),所以在这个柿子中只有\(k\)为未知数

而且可以发现,k越大这个范围的区间肯定越小。因此对于每一维,我们可以通过二分的方法算出\(k\)最大的取值\(lim_d\)。但我们肯定不能直接暴力,不然复杂度会直接爆炸。这里怎么处理到后面再说

对于每一个\(k \in [0, lim_d]\),对答案的贡献即为\(\prod_d{(r_d-l_d+1)}\),其中\(l_d,r_d\)表示\(d\)这维的\(x_d\)能取到的起点上下界。

根据前面的推到,\(r_d - l_d + 1\)是一个关于\(k\)的一次函数,而若干个一次函数乘在一起,就形成了关于\(k\)的一个多项式,我们记作\(f(x) = \prod_d{(r_d-l_d+1)}\),因此答案\(= \sum \limits_{i=1}^{\min\{lim_d\}} {f(i)}\),然后使用插值计算即可。

复杂度\(O(nk)\)

posted @ 2023-08-03 20:41  FOX_konata  阅读(28)  评论(0编辑  收藏  举报