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;
}
posted @ 2022-07-02 16:07  icey_z  阅读(88)  评论(0)    收藏  举报