[CF2053C] Bewitching Stargazer 题解
我们不妨直接递归模拟算答案。
定义 \(f(l, r)\) 表示左右端点为 \(l,r\) 的答案。记 \(mid \gets \lfloor \frac{l+r}{2} \rfloor\),于是:
\[f(l, r) = \begin{cases}
f(l, mid)+f(mid+1,r) & (r-l+1) \equiv 0 \pmod 2 \\
f(l, mid-1) + f(mid+1, r) + mid & {\text {otherwise.}}
\end{cases}
\]
这样做显然会 T,考虑如何优化。我们注意到每次由 \(mid\) 分割,左右两边是对称的。显然,\(mid\) 右边所有取到的点都可以由左边平移得到。设区间长度是 \(len\),这个平移量 \(d\) 就是 \(\lceil \frac{len}{2} \rceil\)。设左(右)边取到了 \(c\) 个点,故右边的答案就是左边的答案加上 \(d \cdot c\)。
于是改写一下函数,将求解函数定义为 pair 型,first 存答案,second 存区间内能取到的个数,直接算就好了。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Linf 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define all(v) v.begin(), v.end()
#define int long long
using namespace std;
//#define filename "xxx"
#define FileOperations() freopen(filename".in", "r", stdin), freopen(filename".out", "w", stdout)
namespace Traveller {
int n, k;
pii operator + (pii a, pii b) { return pii(a.first + b.first, a.second + b.second); }
pii solve(int n) {
if(n < k) return pii(0, 0);
pii res = solve(n/2);
if(n & 1) return res + res + pii(res.second * (1+n >> 1) + (1+n >> 1), 1);
return res + res + pii(res.second * (n >> 1), 0);
}
void main() {
scanf("%lld%lld", &n, &k);
printf("%lld\n", solve(n).first);
}
}
signed main() {
#ifdef filename
FileOperations();
#endif
int _;
cin >> _;
while(_--) Traveller::main();
return 0;
}

浙公网安备 33010602011771号