AtCoder ABC322G 数学 + 暴力

题意

传送门 AtCoder ABC322G Two Kinds of Base

题解

根据 1 ≤ X 1\leq X 1X,以及 f ( S , a ) f(S,a) f(S,a) 关于 a a a 的递增性,可以得到 b < a bb<a。此时 S i < min ⁡ ( 10 , a , b ) S_i<\min(10,a,b) Si<min(10,a,b) 简化为 S i < m i n ( 10 , b ) S_iSi<min(10,b)。根据 S 1 ≠ 0 S_1\neq 0 S1=0,可以观察到 k k k 规模为 O ( log ⁡ X ) O(\log X) O(logX)

先考虑 k k k 较小的情况。当 k = 1 k = 1 k=1,由于 0 < X 00<X 故无解;当 k = 2 k = 2 k=2,则 ( a − b ) S 1 = X (a-b)S_1=X (ab)S1=X,枚举 S 1 , S 2 S_1, S_2 S1,S2,则 a a a 的最小值为 max ⁡ ( S 1 , S 2 ) + 1 + X / S 1 \max(S_1, S_2) + 1 + X/S_1 max(S1,S2)+1+X/S1,最后根据 a ≤ N a\leq N aN 统计答案即可。

k ≥ 3 k\geq 3 k3,则满足 a 2 − b 2 ≤ X a^2-b^2\leq X a2b2X,令 d = a − b d = a - b d=ab,则有 2 b + d ≤ X / d 2b+d\leq X/d 2b+dX/d,可以推出满足条件的 ( a , b ) (a,b) (a,b) 数目为 O ( X log ⁡ X ) O(X\log X) O(XlogX)。那么枚举满足 d ∣ X d|X dX d d d,再根据上界枚举 b b b 即可得到所有的 ( a , b ) (a,b) (a,b) 二元组。问题转化为 a , b a,b a,b 固定后满足条件的 S S S 数量,由于 S i S_i Si 上界为 b − 1 b-1 b1,同时根据等比数列求和公式,可以得到 a k − b k > ( b − 1 ) ∑ i = 0 k − 1 ( a i − b i ) a^k-b^k>(b-1)\sum_{i = 0}^{k-1}(a^i-b^i) akbk>(b1)i=0k1(aibi),可以推出满足条件的 S k , S k − 1 , ⋯   , S 2 S_k,S_{k-1},\cdots,S_2 Sk,Sk1,,S2 至多有一种可能,按照 k k k 从大到小依次减去 a k − b k a^k-b^k akbk 的贡献,判断 f ( S , a ) − f ( S , b ) = X f(S,a)-f(S,b)=X f(S,a)f(S,b)=X 是否成立即可,若成立,对答案贡献为 min ⁡ ( 10 , b ) \min(10,b) min(10,b)。总时间复杂度 O ( X log ⁡ 2 X ) O(X\log^2 X) O(Xlog2X)

#include 
using namespace std;
constexpr int MOD = 998244353;
using ll = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, x;
    cin >> n >> x;
    ll res = 0;
    for (int s1 = 1; s1 < 10; ++s1) {
        if (x % s1 > 0) {
            continue;
        }
        for (int s2 = 0; s2 < 10; ++s2) {
            int d = x / s1;
            int mn = max(s1, s2) + 1 + d;
            (res += max(0, n - mn + 1)) %= MOD;
        }
    }
    for (int d = 1; d <= x; ++d) {
        if (x % d > 0) {
            continue;
        }
        for (int b = 1, a = b + d; a <= n && (ll)a * a - (ll)b * b <= x; ++b, ++a) {
            vector<int> as, bs;
            ll aa = 1, bb = 1;
            while (aa - bb <= x) {
                as.push_back(aa);
                bs.push_back(bb);
                aa *= a, bb *= b;
            }
            int rem = x;
            for (int i = (int)bs.size() - 1; i > 0; --i) {
                int t = rem / (as[i] - bs[i]);
                if (t >= min(10, b)) {
                    break;
                }
                rem -= t * (as[i] - bs[i]);
            }
            if (rem == 0) {
                res += min(10, b);
            }
        }
    }
    res %= MOD;
    cout << res << '\n';

    return 0;
}

你可能感兴趣的:(数学,基本算法,算法)