題目:求i=1∑ngcd(3i,i),n≤1e21
本文學習了連接這位大佬的博客,本文僅僅是理解他博客的公式後自己的推公式過程
直接求顯然不可以,推一波公式化簡一下。
前置公式:
(1)莫比烏斯公式:若g(x)=x∣d∑f(d),則f(x)=x∣d∑μ(xd)g(d)
(2)歐拉函數與莫比烏斯函數的一個關係式:ϕ(n)=d∣n∑μ(d)⋅⌊dn⌋ ;
(3)i=1∑ni2=6n(n+1)(2n+1)
(4)i=1∑ni=2n(n+1)
(5)若a∣b,b∣c,則a∣c
正式推公式:
i=1∑ngcd(3i,i)
=i=⌊3n⌋3∑ngcd(⌊3n⌋,i)+a=1∑⌊3n⌋−1i=a3∑(a+1)3−1gcd(a,i)
我們看到求解的問題被分爲兩部分,但前後兩部分都有求i=l∑rgcd(a,i)把這部分單獨拿出來求
定義f(l,r,x)=i=l∑r[gcd(i,a)==x]
則i=l∑rgcd(a,i)=x∣a∑xi=l∑r[gcd(i,a)==x]=x∣a∑xf(l,r,x)
對f進行反演一波,構造g(l,r,x)=x∣d∑f(l,r,d)=x∣d∑f(l,r,d)=x∣d∑i=l∑r[gcd(i,a)==d]
由公式(5)可知i只要滿足x∣gcd(i,a)即爲有效貢獻,所以g(l,r,x)=i=l∑r[x∣gcd(i,a)]=⌊xr⌋−⌊xl−1⌋,注意這裏要滿足x∣a,
因爲如果x不是a的因子的話,g(l,r,x)=0
由公式(1)可知f(l,r,x)=x∣d∑μ(xd)g(l,r,d)
因爲如果x不是a的因子的話,g(l,r,x)=0
所以f(l,r,x)==x∣d,d∣a∑μ(xd)(⌊dr⌋−⌊dl−1⌋)
所以i=l∑rgcd(a,i)=x∣a∑xx∣d,d∣a∑μ(xd)(⌊dr⌋−⌊dl−1⌋)=d∣a∑(⌊dr⌋−⌊dl−1⌋)x∣d∑xμ(xd)=d∣a∑(⌊dr⌋−⌊dl−1⌋)ϕ(d)
最後一步就是把x和d的順序調換,本來是先x∣a再x∣d,d∣a轉成先d∣a,再x∣d
到這裏就可以O(a)求i=l∑rgcd(a,i)了,所以求解i=⌊3n⌋3∑ngcd(⌊3n⌋,i)的複雜度爲O(6n)
對於後一段,直接求複雜度仍然很高,需要繼續化簡a=1∑⌊3n⌋−1i=a3∑(a+1)3−1gcd(a,i)=a=1∑⌊3n⌋−1d∣a∑(⌊d(a+1)3⌋−⌊da3−1⌋)ϕ(d)=d=1∑⌊3n⌋−1ϕ(d)i=1∑⌊d⌊3n⌋−1⌋⌊d(di+1)3⌋−⌊ddi3−1⌋)=d=1∑⌊3n⌋−1i=1∑⌊d⌊3n⌋−1⌋(3i2d+3i+1)ϕ(d)
令y=⌊d⌊3n⌋−1⌋且又(4)(5)得後半段爲
a=1∑⌊3n⌋−1i=a3∑(a+1)3−1gcd(a,i)=d=1∑⌊3n⌋−1ϕ(a)(3∗d∗6y(y+1)(2y+1)+32y(y+1)+y)
對y進行分塊處理,整體複雜度也爲O(6n),對ϕ(i)和iϕ(i)前綴和預處理爲O(3n)
所以這道題可以在複雜度O(3n)下完成。
代碼因爲找不到錯誤,對拍對着對着跟原博主的代碼越來越像。
ac代碼:
#include<bits/stdc++.h>
#define db double
#define ui unsigned int
#define ll long long
#define ull unsiged ll
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l)for(int i=r;i>=l;i--)
#define file(x) freopen(#x".in","w",stdout);
#define bug(x) cerr<<#x<<": "<<x<<endl
typedef __int128 int128;
using namespace std;
const int MX = 1e7 + 7;
const int mod=998244353;
ll modulo(ll num, ll MOD = mod) { return ((num%MOD) + MOD) % MOD; }
ll power(ll b, ll e, ll MOD = mod) { ll ans = 1; while (e) { if (e % 2) ans = (ans*b) % MOD; b = (b*b) % MOD; e /= 2; } return ans; }
ll inv(ll num, ll MOD = mod) { return power(modulo(num), MOD - 2, MOD); }
ll gcd(ll a, ll b) { return ((b == 0) ? a : gcd(b, a%b)); }
ll phi[MX];
ll pri[MX],inv2,inv6,iphi[MX],phisum[MX];
bool isp[MX];
int tmp=0;
struct Istream {
template <class T>
Istream &operator >>(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;
return *this;
}
}fin;
struct Ostream {
template <class T>
Ostream &operator <<(T x) {
x<0 && (putchar('-'),x=-x);
static char stack[233];static int top;
for(top=0;x;stack[++top]=x%10+'0',x/=10);
for(top==0 && (stack[top=1]='0');top;putchar(stack[top--]));
return *this;
}
Ostream &operator <<(char ch) {
putchar(ch);
return *this;
}
}fout;
void pre_phi()
{
isp[0]=isp[1]=false;
phi[1]=1;
for(int i=2;i<MX;i++)
{
if(!isp[i])
{
pri[++tmp]=i;
phi[i]=i-1;
}
for(ll j=1;i*pri[j]<MX&&j<=tmp;j++)
{
int ans=i*pri[j];
isp[ans]=true;
if(i%pri[j])
{
phi[ans]=phi[i]*(pri[j]-1);
}
else {
phi[ans]=phi[i]*pri[j];
break;
}
}
}
phisum[1]=1,iphi[1]=1;
for(int i=2;i<MX;i++)
{
iphi[i]=(iphi[i-1]+1ll*i*phi[i]%mod)%mod;
phisum[i]=(phisum[i-1]+phi[i])%mod;
}
}
int128 get_n3(int128 n)
{
int128 l=0,r=1e8,res=1,mid;
while(l<=r)
{
mid=(l+r)/2;
if(int128(mid*mid*mid)<=n)res=mid,l=mid+1;
else r=mid-1;
}
return res;
}
int main()
{
inv2=inv(2),inv6=inv(6);
int t;
pre_phi();
fin>>t;
while(t--){
int128 n;
fin>>n;
ll ans=0;
int128 n3=get_n3(n);
int128 m=n3*n3*n3;
for(ll i=1;i*i<=n3;i++)
{
if(n3%i==0)
{
ans=ans+phi[i]*(n/i-(m-1)/i)%mod;
ll t=n3/i;
if(i*i!=n3)
ans+=phi[t]*(n/t-(m-1)/t)%mod;
ans=ans%mod;
}
}
n3--;
ll j,res;
for(ll i=1;i<=n3;i=j+1)
{
res=n3/i;
j=n3/res;
ans=ans+3*(iphi[j]-iphi[i-1]+mod)%mod*res%mod*(res+1)%mod*(2*res+1)%mod*inv6%mod;
ans=ans+(phisum[j]-phisum[i-1]+mod)%mod*(3*res*(res+1)%mod*inv2%mod+res)%mod;
ans=ans%mod;
}
fout<<ans<<'\n';
//cout<<ans<<endl;
}
}