最努力的活着题解
显然是让活的尽量久的人获得更大的价值更优。
而假设当前轮还剩cntcntcnt个人,那么实际会有⌊cntw⌋\lfloor\frac{cnt}{w}\rfloor⌊wcnt⌋个人被淘汰。这些人的具体的位置我们不关心。
然而,本题若直接进行模拟,在加强后的数据下会超时。
接下来考虑优化:
我们不是每次都只能模拟一轮游戏,而是能一次模拟kkk轮游戏,其中的每一轮淘汰掉bbb个人,即:
bw⩽cnt<(b+1)w(b−1)w⩽cnt−kb<bw
\begin{aligned}
&bw\leqslant cnt < (b+1)w\\
&(b-1)w\leqslant cnt-kb < bw
\end{aligned}
bw⩽cnt<(b+1)w(b−1)w⩽cnt−kb<bw
我们可以由此推出:
k=⌊cnt−bw+bb⌋k=\lfloor\frac{cnt-bw+b}{b}\rfloork=⌊bcnt−bw+b⌋
令已经被淘汰掉的人数为ttt,剩余的数和为SSS,则有:
S=∑i=t+1ni=((t+1)+n)(n−t)2
S=\sum_{i=t+1}^{n}i=\frac{((t+1)+n)(n-t)}{2}
S=i=t+1∑ni=2((t+1)+n)(n−t)
可以从kSkSkS中减去前面的块的总和,来得到ansansans的增量
第一块的和记作AAA:
A=(t+1+t+b)b2
A=\frac{(t+1+t+b)b}{2}
A=2(t+1+t+b)b
注意到之后的每一块的和都是A+Bb2A+Bb^2A+Bb2形式,
由此可以推出所有要减去的块之和为:
s=A∑i=1ki+b2∑i=1k−1i(i+1)2=A(1+k)k2+b22∑i=1k−1i2+i=A(1+k)k2+b22[(k−1)k(2(k−1)+1)6+(k−1)k2]
\begin{aligned}
s
&=A\sum_{i=1}^{k}i+b^2\sum_{i=1}^{k-1}\frac{i(i+1)}{2} \\
&=\frac{A(1+k)k}{2}+\frac{b^2}{2}\sum_{i=1}^{k-1}{i^2+i} \\
&=\frac{A(1+k)k}{2}+\frac{b^2}{2}[\frac{(k-1)k(2(k-1)+1)}{6}+\frac{(k-1)k}{2}] \notag\\
\end{aligned}
s=Ai=1∑ki+b2i=1∑k−12i(i+1)=2A(1+k)k+2b2i=1∑k−1i2+i=2A(1+k)k+2b2[6(k−1)k(2(k−1)+1)+2(k−1)k]
于是
Δans=kS−s
\Delta_{ans}=kS-s
Δans=kS−s
这样做越到后面跳得越快,时间复杂度约为O(n)O(\sqrt{n})O(n),应该可以通过本题
所需的求和公式如下:
∑i=1ki=k(k+1)2∑i=1ki2=k(k+1)(2k+1)6
\begin{aligned}
&\sum_{i=1}^{k}i=\frac{k(k+1)}{2}
\\
&\sum_{i=1}^{k}i^2=\frac{k(k+1)(2k+1)}{6}
\end{aligned}
i=1∑ki=2k(k+1)i=1∑ki2=6k(k+1)(2k+1)
由于数据较大会爆longlonglong longlonglong 因此需要开__int128才行
参考代码如下:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
void print(__int128 x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
void solve() {
long long x,y;
cin >> x >> y;
__int128 n=x, w=y;
__int128 cnt = n;
__int128 t = 0;
__int128 k=0,b=0,A=0,S=0,s=0;
__int128 ans = n * (n + 1) / 2;
while (cnt >= w) {
b=cnt/w;
k=(cnt-b*w+b)/b;
cnt-=k*b;
S=(((t + 1) + n) * (n - t) / 2)*(k);
A=(t+1+t+b)*b/2;
s=A*(1+k)*k/2+(((k-1)*(k)*(2*(k-1)+1)/6+(k-1)*(k)/2)/2)*b*b;
ans += S-s;
t+=b*k;
}
print(ans);
cout << endl;
}
signed main() {
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
int T = 1;
// init();
cin >> T;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号