最努力的活着题解

显然是让活的尽量久的人获得更大的价值更优。
而假设当前轮还剩cntcntcnt个人,那么实际会有⌊cntw⌋\lfloor\frac{cnt}{w}\rfloorwcnt个人被淘汰。这些人的具体的位置我们不关心。

然而,本题若直接进行模拟,在加强后的数据下会超时。

接下来考虑优化:
我们不是每次都只能模拟一轮游戏,而是能一次模拟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} bwcnt<(b+1)w(b1)wcntkb<bw
我们可以由此推出:
k=⌊cnt−bw+bb⌋k=\lfloor\frac{cnt-bw+b}{b}\rfloork=bcntbw+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+1ni=2((t+1)+n)(nt)
可以从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=1ki+b2i=1k12i(i+1)=2A(1+k)k+2b2i=1k1i2+i=2A(1+k)k+2b2[6(k1)k(2(k1)+1)+2(k1)k]
于是
Δans=kS−s \Delta_{ans}=kS-s Δans=kSs
这样做越到后面跳得越快,时间复杂度约为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=1ki=2k(k+1)i=1ki2=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;
}
posted @ 2025-08-11 21:33  yxl1  阅读(0)  评论(0)    收藏  举报  来源