题解 CF1242D 【Number Discovery】

CYJian

2020-03-26 19:15:49

Solution

毒瘤结论题... 先考虑,将 $s$ 数列中的每个数分成两类: 1. 被选出的 $k$ 个数求和加入 $s$ 数列的数。 2. 被从小到大选择加入 $s$ 数列的数。 然后,就有一个牛逼结论: 从 $1$ 开始,每 $k^2+1$ 个数分一个段,即第 $i$ 段包含的数是 $[(k^2+1) \times i+1,(k^2+1) \times(i+1)]$(这里认为 $i$ 从 $0$ 开始),则有,每段中有且仅有一个数,是属于第一类数。 然后考虑证明: 首先,对于 $i=0$,不难发现,其中有且仅有一个第一类数,它的值是 $\frac{k(k+1)}{2}$。 然后考虑计算后面的第一类数。我们如果知道第 $i$ 段的第一类数是 $x$,则可以知道第 $i \times k \sim (i + 1) \times k - 1$ 段中第一类数是啥。 考虑如何求出第 $i \times k + t + 1$ 段中第一类数是谁。 根据题意,我们有: $$ \sum_{j=1}^{k}(i \times (k^2+1)+t\times k+j + [i \times (k^2+1)+t\times k+j \leq x]) $$ 大概化简一下柿子,就有: $$ (i \times k+t) \times (k^2+1)+\frac{k(k+1)}{2} - t + \max(0, \min(k, i \times (k^2+1)+(t+1)\times k-x+1))$$ 然后注意到,$\frac{k(k+1)}{2}-t + \max(0, \min(k, i \times (k^2+1)+(t+1)\times k-x+1)) \in [1,k^2+1]$,所以这个数一定在第 $i \times k + t + 1$ 段中,所以一开始的那个结论也就成立了。 当然,有了这个结论以及这个柿子之后,这个题就能做了: 考虑一次询问 $n$ 和 $k$,我们先算出 $n$ 是在第 $\left\lfloor\frac{n-1}{k^2+1}\right\rfloor$ 段中。然后我们可以用倍增求出这个段中的第一类数是 $V$。如果 $n = V$,则可以直接求出,这个数是在序列中的第 $(\left\lfloor\frac{n-1}{k^2+1}\right\rfloor+1) \times (k+1)$ 项上。 如果 $n \ne V$,则考虑求出 $n$ 前面出现了多少大于它的第一类数。不难发现,由 $n$ 前面的数一共能在 $s$ 中生成 $\left\lfloor\frac{n-1}{k^2+1}\right\rfloor \times k + \frac{((n-1)\bmod(k^2+1))-[n \ge V]}{k}$ 个第一类数。而小于 $n$ 的第一类数共有 $\left\lfloor\frac{n-1}{k^2+1}\right\rfloor + 1 - [n < V]$ 种,然后加减一下就得到 $n$ 所在的位置了。 然后倍增的时候,直接按照上面化简的柿子递归计算就行了。 看起来柿子很恐怖,事实上非常好写。 $\rm Code$: ```cpp inline ll S(ll x, ll k) { return (x + x + k - 1) * k / 2; } inline ll find(ll x, ll k) { if(!x) return k * (k + 1) >> 1; ll p = find(x / k, k), rest = x % k; ll st = (x / k) * (k * k + 1) + rest * k + 1; if(st + k <= p) return S(st, k); else return S(st, k) + min(k, st + k - p); } inline void Solve() { ll n = rl, k = ri, bel = (n - 1) / (k * k + 1); ll p = find(bel, k); if(p == n) cout << (bel + 1) * (k + 1) << endl; else { ll pos = n - bel - 1 + (n < p); ll t = (n - 1) % (k * k + 1) + 1; ll cnt = bel * k + (t - 1 - (n >= p)) / k; cout << pos + cnt << endl; } } int main() { int Case = ri; while(Case--) Solve(); return 0; } ```