AtCoder ABC322G 数学 + 暴力

题意

传送门 AtCoder ABC322G Two Kinds of Base

题解

根据 1 ≤ X 1\leq X 1≤X,以及 f ( S , a ) f(S,a) f(S,a) 关于 a a a 的递增性,可以得到 b < a b<a b<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_i<min(10,b) Si<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 0<X 0<X 故无解;当 k = 2 k = 2 k=2,则 ( a − b ) S 1 = X (a-b)S_1=X (a−b)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 a≤N 统计答案即可。

当 k ≥ 3 k\geq 3 k≥3,则满足 a 2 − b 2 ≤ X a^2-b^2\leq X a2−b2≤X,令 d = a − b d = a - b d=a−b,则有 2 b + d ≤ X / d 2b+d\leq X/d 2b+d≤X/d,可以推出满足条件的 ( a , b ) (a,b) (a,b) 数目为 O ( X log ⁡ X ) O(X\log X) O(XlogX)。那么枚举满足 d ∣ X d|X d∣X 的 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 b−1,同时根据等比数列求和公式,可以得到 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) ak−bk>(b−1)∑i=0k−1(ai−bi),可以推出满足条件的 S k , S k − 1 , ⋯   , S 2 S_k,S_{k-1},\cdots,S_2 Sk,Sk−1,⋯,S2 至多有一种可能,按照 k k k 从大到小依次减去 a k − b k a^k-b^k ak−bk 的贡献,判断 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)。

cpp 复制代码
#include <bits/stdc++.h>
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;
}
相关推荐
风中的微尘3 小时前
39.网络流入门
开发语言·网络·c++·算法
西红柿维生素3 小时前
JVM相关总结
java·jvm·算法
ChillJavaGuy5 小时前
常见限流算法详解与对比
java·算法·限流算法
sali-tec5 小时前
C# 基于halcon的视觉工作流-章34-环状测量
开发语言·图像处理·算法·计算机视觉·c#
你怎么知道我是队长6 小时前
C语言---循环结构
c语言·开发语言·算法
艾醒7 小时前
大模型面试题剖析:RAG中的文本分割策略
人工智能·算法
纪元A梦9 小时前
贪心算法应用:K-Means++初始化详解
算法·贪心算法·kmeans
_不会dp不改名_9 小时前
leetcode_21 合并两个有序链表
算法·leetcode·链表
mark-puls9 小时前
C语言打印爱心
c语言·开发语言·算法
Python技术极客9 小时前
将 Python 应用打包成 exe 软件,仅需一行代码搞定!
算法