CF468C Hack it!
CF468C Hack it!
大致题意
输入\(a\),构造一组\([l,r]\),满足\(\sum_{i = l}^r f(i) \equiv 0 \pmod{a}\),\(f(i)\)为一个函数求一个数的各数位和。
\(1 \leq l\leq r\leq 10^{200}\),\(1\leq m \leq 10^{18}\)
解题思路(二分)
先考虑确定左端点\(l\)为1,然后用二分的方法,找到最小的\(r\)满足\(\sum_{i = l}^r f(i) >= a\),不难发现\(r\)的取值不会超过长整型范围。然后在区间上进行双指针的递增,即可找到答案。
为什么这样的时间复杂度是对的呢?我也不知道(((
根据出题人的说法:数位和的变化比较随机,没有出现明显的循环节,所以变两下就会变到正确答案。
于是这道题就愉快的做完了
解题思路 (直接计算)
除了可以二分外,这道题也同样可以用数学方法推公式直接计算。
参考题解 CF468C 【Hack it!】 - da32s1da 的博客
因为有\(f(x) = y\),所以很自然的可以推出\(f(x + 10^{18}) =f(x) + 1\),并以此类推可以得到
\(f(x + 10^{18} + 1) =f(x) + 2\)
\(f(x + 10^{18} + 2) =f(x) + 3\)
\(...\)
所以对于原式,我们可以得到,\(\sum_{i = 1}^{10^{18}} f(i) \equiv \sum_{i = 0}^{10^{18} -1} f(i) + 1 \pmod{a}\)
以此类推
\(\sum_{i = 2}^{10^{18} + 1} f(i) \equiv \sum_{i = 0}^{10^{18} -1} f(i) + 2 \pmod{a}\)
\(...\)
我们设\(\sum_{i = 0}^{10^{18} -1} f(i) = p\)
经过一系列式子的变换,就可以得到\(\sum_{i = a-p}^{10^{18} + a- p-1} f(i) \equiv 0 \pmod{a}\),(具体过程可以参考上面那篇博客)
\(a-p\)和\(10^{18} + a- p-1\)即为我们所求的\([l,r]\)值。
\(p\)为一定值,我们可以手动计算(当然也可以借助数位dp程序),得到\(p = 81*10^{18}\mod a\)
于是就可以很简洁地完成这道题。
代码(二分)
/* Generated by powerful Codeforces Tool
* You can download the binary file in here https://github.com/xalanq/cf-tool (Windows, macOS, Linux)
* Author: icey_z
* Time: 2022-07-02 14:06:30
**/
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
ll mod;
ll cal(ll x)
{
ll ans = 0;
for (ll i = 1; i <= x; i *= 10LL) { //低到高枚举位
ll p = x / (i * 10); //低位的和
ans += 45 * i * p;
ll q = (x / i) % 10;
for (int j = 1; j < q; j++) { //当前位的和
ans += j * i;
}
ll t = x - (x / i) * i; //高位的和
ans += (t + 1) * q;
}
return ans;
}
ll calc(ll x)
{
ll ans = 0;
while (x) {
ans += x % 10;
x /= 10;
}
return ans;
}
void solve()
{
cin >> mod;
ll l = 1, r = 1e17;
ll res = 0;
while (l <= r) {
ll mid = (l + r) / 2;
if (cal(mid) >= mod) {
res = mid;
r = mid - 1;
}
else
l = mid + 1;
}
r = res;
l = 1;
ll cur = cal(r);
// cout << l << " " << r << "\n";
while (cur != mod) {
cur -= calc(l++);
while (cur < mod) {
cur += calc(++r);
}
}
cout << l << " " << r << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
t = 1;
while (t--) {
solve();
}
return 0;
}