HDU6588 经典gcd求和

本文探讨了如何高效计算特定形式的数学表达式∑i=1ngcd(floor(i^(1/3)),i)mod998244353,n=10^21。通过引入前缀和的概念,将问题转化为更易处理的形式,并利用欧拉函数和差分技巧降低计算复杂度。最终,提出了一种时间复杂度为O(1e7+T*(1e7+√1e7))的解决方案。

需要求

∑i=1ngcd⁡(⌊i3⌋,i)mod  998244353n=1021 \sum_{i=1}^n\gcd(\lfloor{\sqrt[3]{i}}\rfloor,i)\mod 998244353 \quad n = 10^{21} i=1ngcd(3i,i)mod998244353n=1021

思路

m=⌊n3⌋−1m=\lfloor \sqrt[3]{n} \rfloor-1m=3n1

∑i=1ngcd(floor(i3),i)=∑i=1m∑j=i3(i+1)3−1gcd(i,j)+∑i=(m+1)3ngcd(m+1,i)\sum_{i=1}^{n}gcd(floor(\sqrt[3]{i}),i) = \sum_{i=1}^{m}\sum\limits_{j=i^{3}}^{(i+1)^{3}-1}gcd(i,j) \quad + \quad \sum\limits_{i=(m+1)^{3}}^{n}gcd(m+1,i)i=1ngcd(floor(3i),i)=i=1mj=i3(i+1)31gcd(i,j)+i=(m+1)3ngcd(m+1,i)

考虑一个函数(前缀和,差分后即为上面部分所求,这个想法也比较自然),f(n)=∑i=1ngcd(m,i)f(n) = \sum_{i=1}^ngcd(m,i)f(n)=i=1ngcd(m,i)
f(n)=∑i=1ngcd(m,i)=∑i=1n∑d∣gcd(m,i)ϕ(d)=∑d∣mϕ(d)∗⌊nd⌋ f(n) = \sum_{i=1}^ngcd(m,i) \\ = \sum_{i=1}^n \sum_{d|gcd(m,i)}\phi(d) \\ = \sum_{d|m} \phi(d)*\left \lfloor \frac{n}{d} \right \rfloor f(n)=i=1ngcd(m,i)=i=1ndgcd(m,i)ϕ(d)=dmϕ(d)dn
则 :
注意下面的,m=⌊n3⌋−1m=\lfloor \sqrt[3]{n} \rfloor-1m=3n1
∑i=1ngcd(floor(i3),i)=∑i=1m∑j=i3(i+1)3−1gcd(i,j)+∑i=(m+1)3ngcd(m+1,i)=∑i=1m∑d∣iϕ(d)∗[⌊(i+1)3−1d⌋−⌊i3−1d⌋]+∑d∣m+1ϕ(d)∗[⌊nd⌋−⌊(m+1)3−1d⌋]=∑d=1mϕ(d)∗∑i=1⌊m/d⌋[⌊(id+1)3−1d⌋−⌊(id)3−1d⌋]+∑d∣m+1ϕ(d)∗[⌊nd⌋−⌊(m+1)3−1d⌋]=∑d=1mϕ(d)∗∑i=1⌊m/d⌋[3di2+3i+1(注意这里是下取整)]+∑d∣m+1ϕ(d)∗[⌊nd⌋−⌊(m+1)3−1d⌋] \sum_{i=1}^{n}gcd(floor(\sqrt[3]{i}),i) = \sum_{i=1}^{m}\sum\limits_{j=i^{3}}^{(i+1)^{3}-1}gcd(i,j) \quad + \quad \sum\limits_{i=(m+1)^{3}}^{n}gcd(m+1,i) \\ = \sum_{i=1}^{m}\sum_{d|i}\phi(d)*\left [ \left \lfloor \frac{(i+1)^3 -1}{d} \right \rfloor - \left \lfloor \frac{i^3-1}{d} \right \rfloor \right ] \quad + \quad \sum_{d|m+1}\phi(d)*\left [ \left \lfloor \frac{n}{d} \right \rfloor - \left \lfloor \frac{(m+1)^3-1}{d} \right \rfloor \right ] \\ = \sum_{d=1}^{m}\phi(d)*\sum_{i=1}^{ \lfloor m/d \rfloor}\left [ \left \lfloor \frac{(id+1)^3 -1}{d} \right \rfloor - \left \lfloor \frac{(id)^3-1}{d} \right \rfloor \right ] \quad + \quad \sum_{d|m+1}\phi(d)*\left [ \left \lfloor \frac{n}{d} \right \rfloor - \left \lfloor \frac{(m+1)^3-1}{d} \right \rfloor \right ] \\ = \sum_{d=1}^{m}\phi(d)*\sum_{i=1}^{ \lfloor m/d \rfloor}\left [ 3di^2 + 3i + 1(注意这里是下取整) \right ] \quad + \quad \sum_{d|m+1}\phi(d)*\left [ \left \lfloor \frac{n}{d} \right \rfloor - \left \lfloor \frac{(m+1)^3-1}{d} \right \rfloor \right ] i=1ngcd(floor(3i),i)=i=1mj=i3(i+1)31gcd(i,j)+i=(m+1)3ngcd(m+1,i)=i=1mdiϕ(d)[d(i+1)31di31]+dm+1ϕ(d)[dnd(m+1)31]=d=1mϕ(d)i=1m/d[d(id+1)31d(id)31]+dm+1ϕ(d)[dnd(m+1)31]=d=1mϕ(d)i=1m/d[3di2+3i+1()]+dm+1ϕ(d)[dnd(m+1)31]
因此可以计算 ,时间复杂度O(1e7+T∗(1e7+1e7)O(1e7 + T*(1e7+\sqrt{1e7})O(1e7+T(1e7+1e7) 其中TTT为数据组数,最左边的1e71e71e7为预处理欧拉函数的时间。

本题的关键在于推导的倒数第二行变换贡献,从枚举iii变为枚举ddd,使得复杂度降了下来

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 lll;
const int mod = 998244353;
const int inv2 = 499122177;
const int inv6 = 166374059;
const int maxn=1e7+10;
template <class T>
void read(T &x) {
	static char ch;static bool neg;
	for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
	for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
	x=neg?-x:x;
}
lll n;
int tot;
bool valid[maxn];//is prime or not
int phi[maxn];// phi
int ans[maxn];// prime
void getprime(int n)
{
    tot=0;
    phi[1]=1;
    memset(valid,true,sizeof(valid));
    for(int i=2;i<=n;++i){
        if(valid[i]){
            tot++;
            ans[tot]=i;
            phi[i]=i-1;//i为素数
        }
        //下面的主角是小于等于i的每个质数
        for(int j=1;(j<=tot) && (i*ans[j]<=n);++j){
            valid[i*ans[j]]=false;
            if(i%ans[j]==0){//ans[j]是i的素因子
                phi[i*ans[j]]=phi[i]*ans[j];
                break;//如果整除就break;
            }
            else phi[i*ans[j]]=phi[i]*(ans[j]-1);
        }
    }
}
lll pow3(lll x)
{
    return x*x*x;
}
//n(n+1)(2n+1)/6
ll solve(int d, ll m){
    ll up = m/d;
    ll ans1 = (1+up)*up%mod*inv2%mod;
    ll ans2 = d*up%mod*(up+1)%mod*(2*up+1)%mod*inv6%mod;
    return ((ans1+ans2)*3 + up)%mod;
}
int main()
{
    getprime(1e7);
    int t;
    cin>>t;
    while(t--)
    {
        read(n);
        int m = pow(n,1.0/3) - 1e5;
        for(;pow3(m)<=n;m++);
        m-=2;
        ll ans = 0;
        for(int d=1;d<=m;++d){
            ans=(ans + 1LL*phi[d]*solve(d,m)%mod)%mod;
        }
        ll res = 0;
        int now=m+1;
        for(int i=1;i*i<=now;++i){
            if(now%i==0){//i now/i
                res = (res + 1LL*phi[i]*((n/i-(pow3(m+1)-1)/i)%mod) )%mod;
                if(i*i!=now) res = (res + 1LL*phi[now/i]*((n/(now/i)-(pow3(m+1)-1)/(now/i))%mod) )%mod;
            }
        }
        ans = (ans + res)%mod;
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值