P11499 题解
与现有两篇题解的思路不同,我使用了分块思维,没有写大型分讨,自认为代码和思路比较清新。
声明:此做法不卡常,其时间复杂度为
思路
把整个添加功率的过程几何化,相当与把一个在数轴上的点从
所有不可到达的点把数轴分成了若干段,定义其中第
这样从
- 从
a 走到它所在区间的末尾。 - 从
a 所在区间的下一个区间走到b 所在区间的上一个区间。 - 从
b 所在区间的开头走到b 。
当然,如果
a,b 在同一个区间,要进行特判,因为三个阶段会有重叠部分。
通过简单推导可以得出,第一段的区间为
第二段是最麻烦的,首先得出:
然后开始暴力走。我们的目标是从
- 从
p 区间第一个位置走到p 区间最后一个位置,花费calc(1, c-1) 步。 - 进行一次 Y 操作,从
p 区间最后一个位置走到p+1 区间第一个位置。 - 从
p+1 区间第一个位置走到p+1 区间最后一个位置,花费calc(1, c-1) 步。 - 进行一次 Y 操作,从
p+1 区间最后一个位置走到p+2 区间第一个位置。 - 从
p+2 区间第一个位置走到p+2 区间最后一个位置,花费calc(1, c-1) 步。 - 进行一次 Y 操作,从
p+2 区间最后一个位置走到p+3 区间第一个位置。 - ......
看到规律了吗?每两次操作为一个周期,共有
最后把三个阶段的答案加在一起,这个题就做完了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a, b, c;
ll calc(ll l, ll r) {
ll dt = r - l;
if (dt % 2 == 0) return dt / 2;
return dt / 2 + 1;
}
int main() {
cin >> a >> b >> c;
if (a / c == b / c) {
cout << calc(a, b) << "\n";
return 0;
}
ll ans = 0;
// a -> (a / c + 1) * c - 1
ans += calc(a, (a / c + 1) * c - 1) + 1;
// now pos: (a / c + 1) * c + 1;
ans += (calc(1, c-1) + 1) * ((b / c) - (a / c + 1));
// now pos: (b / c) * c + 1
ans += calc((b / c) * c + 1, b);
cout << ans << "\n";
return 0;
}