ICPC 2019 银川 F - Function! 题解

ICPC 2019 银川 F - Function! 题解

更好的阅读体验戳此进入

(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)

题目链接

题意

对于给定函数:

\[f_a(x) = a^x \quad (a > 0 \land a \ne 1) \]

对于给定的 $ n \ (n \le 10^{12}) $ 求如下式子的值

\[\sum^n_{a = 2}(\ a \times \sum^n_{b = a}\lfloor f_a^{-1}(b) \rfloor \times \lceil f_b^{-1}(a) \rceil \ ) \]

前置知识

反函数(逆函数)

对于函数 $ f(x) $,记 $ f^{-1}(x) $ 为 $ f(x) $ 的反函数。可以简单的将其理解为把 $ f(x) $ 的定义域与值域的映射关系调换一下就是 $ f^{-1}(x) $ 了。

对于本题的 $ f(x) $ 显然指数函数的反函数即对数函数,可以这样理解:

对于 $ f_a(x) = a^x $,可以通俗地理解为 $ x $ 为自变量,$ a^x $ 为因变量,调换后可以认为是 $ f{-1}_a(ax) = x $,令 $ \xi = a^x $,则有 $ f_a^{-1}(\xi) = \log_a^\xi $。

逆元

TODO

对于求逆元的方法,以及除数较小时如何不用逆元,这里不再赘述,以后有时间可能开个逆元的坑。

分析

简单的转换

由前置知识可以得出题目中的式子等价于如下式子:

\[\sum^n_{a = 2}(\ a \times \sum^n_{b = a}\lfloor \log_a^b \rfloor \times \lceil \log_b^a \rceil \ ) \]

Tips

值得一提的是,本体因为输入数据只有一个数,所以可以考虑用数据库的思想,理论上在空间限制内,可以通过暴力程序,将结果以初始化数组的形式打印到文件里,这样的做法可以完全避免范围内的 $ TLE $,但是当考虑到文件大小的限制 $ 100KB $ 和本地跑暴力程序效率的限制,最多只能跑到 $ 1 \times 10^4 $ 左右。

$ O(n^2) $ 做法

显然直接枚举 $ a, b $ 即可,理论上可以跑 $ 10^4 $ 以内的数据。

$ O(n) $ 做法

考虑题中式子的性质:

显然我们可以看出显然有如下性质 $ b \ge a $。

则显然有

\[\log_b^a \in \left( 0, 1 \right] \]

\[\lceil \log_b^a \rceil = 1 \]

类比这个性质我们考虑 $ \log_a^b $,可以发现如下性质:

\[\log_a^b \in \left[ 1, 2 \right) \quad (a > \sqrt{n}) \]

\[\lfloor \log_a^b \rfloor = 1 \quad (a > \sqrt{n}) \]

通过这两个性质原式可以转化为如下:

\[\begin{aligned} \sum^n_{a = 2}(\ a \times \sum^n_{b = a}\lfloor \log_a^b \rfloor \times \lceil \log_b^a \rceil \ ) &= \sum^n_{a = 2}(\ a \times \sum^n_{b = a}\lfloor \log_a^b \rfloor \ ) \quad (a > \sqrt{n}) \\ &= \sum^n_{a = \lfloor \sqrt{n} \rfloor + 1}(\ a \times \sum^n_{b = a}\lfloor \log_a^b \rfloor \ ) \\ &= \sum^n_{a = \lfloor \sqrt{n} \rfloor + 1}(\ a \times \sum^n_{b = a} 1 \ ) \\ &= \sum^n_{a = \lfloor \sqrt{n} \rfloor + 1}(\ a \times (n - a + 1) \ ) \\ &= (n + 1) \times \sum^n_{a = \lfloor \sqrt{n} \rfloor + 1}a \quad - \quad \sum^n_{a = \lfloor \sqrt{n} \rfloor + 1}a^2 \\ &= (n + 1) \times \sum^n_{a = \lfloor \sqrt{n} \rfloor + 1}a \quad - \quad ( \sum^n_{a = 1}a^2 - \sum_{a = 1}^{ \lfloor \sqrt{n} \rfloor}a^2) \\ &= (n + 1) \times \dfrac{1}{2} \times ( \lfloor \sqrt{n} \rfloor + 1 + n) \times (n - ( \lfloor \sqrt{n} \rfloor + 1 ) + 1) \ -\\ &\quad \quad ( \dfrac{n(n + 1)(2n + 1)}{6} - \dfrac{ \lfloor \sqrt{n} \rfloor \times ( \lfloor \sqrt{n} \rfloor + 1) \times (2 \times \lfloor \sqrt{n} \rfloor + 1)}{6} ) \\ \end{aligned} \]

这里还可以继续化简,不过那就是常数问题了,显然现在这个式子可以直接 $ O(1) $ 求。

这时如果将 $ a \le \sqrt{n} $ 的部分暴力求,时间复杂度即为 $ O((\sqrt{n})^2) = O(n) $,理论上可以过 $ 1 \times 10^8 $ 的点。

$ O(\sqrt{n} \log{n}) $ 做法

观察以 $ a $ 为底的对数函数图像:

Function_1.png

显然对于 $ \lfloor \log_a^b \rfloor $,由于下取整的性质,显然可以根据值域,将定义域分为若干段,即将 $ b $ 分为如下几个区间:

\[\left[ a^1, a^2 \right), \ \left[ a^2, a^3 \right), \ \left[ a^3, a^4 \right), \ \cdots,\ \left[ a^{\lfloor \log_a^n \rfloor} , n \right] \]

显然对于每个区间的值域都有且只有一个值,即:

\[1, \ 2, \ 3, \ \cdots, \ \lfloor \log_a^n \rfloor \]

这样我们便可以以此为基础进行优化,将对应值乘上区间内值的数量在计算即可。

注意

整除

关于式子中的除法是否可以整除,可以从很多个角度来理解。

  1. 由于我们的式子是从整式推过来的,所以显然最后的结果一定是个整数,所以必定可以整除。
  2. 由于题中需要取模,所以考虑模运算一般都不考虑浮点数,故可不严谨地认为其可以整除。
  3. 通过数学严谨地证明,可以考虑将除数分解后分别讨论被除数是否存在其因数,一般通过枚举被除数某个项对除数的因子取模的值来证明。

带模除法

这部分很显然,具体做法不再赘述,将除法改为乘逆元即可。

log 精度问题

如果按正解做会发现我们根本不需要计算 log 的值,所以不会有这个问题,但是如果选择 $ O(n) $ 甚至更暴力的做法就需要考虑到这一点了。

很多时候我们喜欢用换底公式来简单地表示出任意一个 log 的值,但是这样的求法对于单次使用精度还可以接受,但是对于本题,会随着 n 的增大逐渐放大这样做法的精度误差(我模拟赛的时候就因为这个而 0pts 了)

不过这个我并没有想到高效且正确的方法,类似 BitScanReverse 这种的奇淫巧计也都是 VS 里面的,OI 用不了,能想到的只有用 long double 或者 float128 之类的东西,或者干脆递归手写求 log。

就像我写的正解里面被我注释掉的那一段代码,如果那一段的思路没有假掉了的话,那么就也是 log 炸精度了。

对于取模

这道题里的 $ n $ 读入就已经是 $ long \ long $ 的范围了,所以用到的时候都要取模,并且管理好优先级,否则很容易计算过程中爆 $ long \ long $ 导致 WA。

AC Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
// #include <quadmath.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define MOD 998244353

/******************************
abbr

******************************/

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;

#define int ll
#define sqrt sqrtl
#define floor floorl
#define ceil ceill
#define log logl

#define sqrtN (ll)(floor((long double)(sqrt(n))))

#define logg(a, b) (ll)(floor(log((long double)b) / log((long double) a))) 

int qpow(int a, int b){
    ll ret(1), mul(a);
    while(b){
        if(b & 1)ret = ret * mul % MOD;
        b >>= 1;
        mul = mul * mul % MOD;
    }
    return int(ret);
}

const int inv_2 = qpow(2, MOD - 2);
const int inv_6 = qpow(6, MOD - 2);

ll CalFunc(ll n){
    ll left = (n + 1) % MOD * (ll)inv_2 % MOD * ((sqrtN + n + 1)%MOD) % MOD * (ll(-sqrtN + n)%MOD) % MOD;
    ll rightl = n % MOD * ((n + 1) % MOD) % MOD * ((2 * n + 1) % MOD) % MOD * inv_6 % MOD;
    ll rightr = sqrtN % MOD * ((sqrtN + 1)%MOD) % MOD * ((2 * sqrtN + 1)%MOD) % MOD * (inv_6 % MOD) % MOD;
    ll right = (rightl - rightr + MOD) % MOD;
    return (left - right + MOD) % MOD;
}

template<typename T = int>
inline T read(void);

signed main(){
    int N = read();
    int ans(0ll);
    for(int a = 2; a * a <= N; ++a){
        // int tmpp(0);
        // for(int k = 1; k < logg(a, N); ++k){
        //     int tmp = (qpow(a, k + 1) - qpow(a, k) + MOD) % MOD;
        //     tmpp = (tmpp + tmp) % MOD; 
        // }
        // tmpp = ((N - qpow(a, logg(a, N)) + 1) % MOD + tmpp) % MOD;
        // ans = (ans + tmpp * a % MOD) % MOD; 
        ll tmp(1ll);
        for(int b = a; b <= N; b *= a, ++tmp){
            ans = (ans + (min(b * a - 1, N) - (b - 1) + MOD) % MOD * tmp % MOD * a % MOD) % MOD;
        }
    }
    ans = (ans + CalFunc(N)) % MOD;

    printf("%lld\n", ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template<typename T>
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_08_25 初稿

update-2022_08_25 小优化

posted @ 2022-09-20 10:57  Tsawke  阅读(55)  评论(0编辑  收藏  举报