题目链接
题意
定义f(x)为x在十进制下的各位数字之和。
给定a,需要你给出一个l,r(1 <= l <= r <= 1e200)使得(f(l) + … +f(r))能被a整除。
题目确保有解。
数据
(1 <= a <= 1e18)
输入
46
126444381000032
输出
1 10
2333333 2333333333333
解题方法:
姿势1:[一套尺取+二分连招]
令s(x) = f(1)+f(2)+…+f(x)。
我们只需找到s(R)%a = s(L-1)%a就美滋滋了
我们使用二分查询找到最小的且满足g(R)>=a
的值R, 接下来令L=1,然后跑一个双指针,调整
L,R的值即可。至于s(x)怎么求,我们把每一个
数位对答案的贡献加起来即可。
姿势2:[构造]
注意到f(x+1e18)=f(x)+1。
故s(x+1e18)=s(1e18)+s(x)+x。
即s(x+1e18)-s(x) = s(1e18)+x
再注意到:s(10^x)= 4510^(x-1) x + 1
L = a-s(1e18)%a+1,R = L + 1e18- 1
于是一组合法解就神不知鬼不知觉地构造出来了
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a;
LL g(LL x)//计算g(x)这里想了好久好久
{
LL ans = 0;
for(LL ten = 1; ten <= x; ten *= LL(10)){
LL dig = (x / ten) % (LL)10;
LL cur = 0;
LL m = x / ((LL)10 * ten);
LL n = x % ten;
for(LL i = 1; i < dig; i++) cur += i;
ans += (m + 1) * cur * ten;
ans += dig * (m * ten + n + 1);
for(LL i = dig + 1; i <= 9; i++){
ans += m * ten * i;
}
}
return ans;
}
LL getDig(LL x)
{
LL ans = 0;
while(x)
{
ans += x % 10;
x /= 10;
}
return ans;
}
int main()
{
cin >> a;
LL l = 1, r = 1e17;
while(l < r)
{
LL mid = (l + r) >> 1;
if(g(mid) < a){
l = mid + 1;
}
else{
r = mid;
}
}
l = 1;
LL sum = g(r) - g(l - 1);
while(1)
{
if(sum < a){
sum += getDig(++r);
}
else if(sum > a){
sum -= getDig(l++);
}
else{
break;
}
}
cout << l << " " << r << endl;
return 0;
}