2019 acm-icpc银川站F.Function!(数学分块)

给你一个式子 a = 2 n ( a b = a n f a 1 ( b ) f b 1 ( a ) ) \sum_{a=2}^n{\left( a \sum_{b=a}^n{\lfloor f_{a}^{-1}\left( b \right) \rfloor}\lceil f_{b}^{-1}\left( a \right) \rceil \right)} 让你求值。
f a ( b ) = a b , f a 1 ( b ) = l o g a b f_a(b)=a^b,f_a^{-1}(b)=log_ab

我们首先观察一下这个式子,显然 b a , f b 1 ( a ) = 1 \because b\geq a,\therefore\lceil f_{b}^{-1}\left( a \right) \rceil=1
那么化简一下这个式子就是 a = 2 n a b = a n l o g a b \sum_{a=2}^n{a \sum_{b=a}^n{\lfloor log_ab \rfloor} } ,显然右边的对数函数是可以分块计算的,枚举 a a ,对于每个 a a ,每次枚举对数函数的答案然后跳即可。当计算到 a a > n a*a > n 的时候,那么整个 b = [ a , n ] b=[a,n] 的对数答案显然都是1了,这个时候直接 O ( 1 ) O(1) 计算即可。
注意中间的取模细节。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
LL n;
const LL mod = 998244353;
LL pd(LL a,LL b){
    LL ans=1;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
LL get(LL x){
    x%=mod;
    LL inv=pd(6,mod-2);
    return x%mod*(x+1)%mod*(2*x+1)%mod*inv%mod;
}
int main() {
    ios::sync_with_stdio(false);
    cin>>n;
    LL ans=0;
    LL inv=pd(2,mod-2);
    for(LL i=2;i<=n;i++){
        LL res=1;
        if(i*i>n){
            LL q=n%mod;
            ans=ans+(q+1)%mod*(i+q)%mod*(q-i%mod+1+mod)%mod*inv%mod;
            ans=ans-(get(n)-get(i-1)+10ll*mod)%mod+10ll*mod;
            ans%=mod;
            break;
        }
        for(LL l=i,tmp=0;l<=n;l=res,tmp++){
            res*=i;
            if(res>n){
                ans=ans+i%mod*tmp*(n%mod-l+1+mod)%mod;
                break;
            }else{
                ans=ans+i%mod*tmp*(res%mod-l+mod)%mod;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}
发布了160 篇原创文章 · 获赞 81 · 访问量 9682

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/102835535
今日推荐