P3441【HN Training 2015 Round5】lucas的數論
問題描述
數據範圍
對於100%的數據:n<=1000000000
直接推式子,用到一個公式,這個公式也比較顯然,就是根據定義直接得到,注意到不互質的數對乘積也一定會被乘積相同的一個互質數對算到。
注意到後面是取整的形式,如果知道 和 的前綴和,那麼可以分塊在 內求解
考慮如何快速求出 的前綴和與 的前綴和,考慮杜教篩。
對於 ,注意到 ,那麼有 ,於是
上式顯然可以分塊迭代處理,預處理一部分後做到 ,從狄利克雷卷積的角度就是
對於 ,注意到 ,即 ,那麼 ,即 ,同樣有 ,於是
上式顯然還是分塊迭代處理,但是需要用到 的前綴和,複雜度不好說,但還是比較快的。
關於預處理一部分 ,線性篩的時候需要增加兩個數組,一個記錄 的最小質因子,另一個記錄最小質因子的指數,由於線性篩每次篩掉一個數一定是用他的最小質因數,因此可以方便的轉移,具體可以看代碼。
事實上,求 的前綴和有更快的方法,因爲 ,直接分塊+預處理可以做到 ,最終複雜度 ,複雜度並不會證,看看就好。
代碼(杜教篩求 ):
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
#define N 12345678
#define ll long long
using namespace std;
const ll mod=1e9+7;
map<ll,ll>Mu,G;
ll n,K,tot,P[N],g[N],mu[N],pc[N],pd[N];
void EU()
{
ll i,j;mu[1]=g[1]=1;
for(i=2;i<=K;i++)
{
if(!g[i])P[++tot]=i,mu[i]=-1,g[i]=2,pc[i]=1,pd[i]=tot;
for(j=1;j<=tot&&i*P[j]<=K;j++)
{
if(i%P[j])
{
pc[i*P[j]]=1;
pd[i*P[j]]=j;
mu[i*P[j]]=-mu[i];
g[i*P[j]]=g[i]<<1;
}
else
{
pc[i*P[j]]=j==pd[i]?pc[i]+1:1;
pd[i*P[j]]=j;
g[i*P[j]]=j==pd[i]?(g[i]/(pc[i]+1)*(pc[i]+2)):(g[i]<<1);
}
}
}
for(i=2;i<=K;i++)g[i]+=g[i-1],mu[i]+=mu[i-1],g[i]%=mod;
}
ll Gmu(ll x)
{
if(x<=K)return mu[x];
if(Mu[x])return Mu[x];
ll i,j,ans=1;
for(i=2;i<=x;i=j+1)
{
j=x/(x/i);
ans-=(j-i+1)*Gmu(x/i);
}
return Mu[x]=ans;
}
ll Gg(ll x)
{
if(x<=K)return g[x];
if(G[x])return G[x];
ll i,j,ans=x;
for(i=2;i<=x;i=j+1)
{
j=x/(x/i);
ans-=(Gmu(j)-Gmu(i-1))*Gg(x/i)%mod;ans%=mod;
}
return G[x]=ans;
}
int main()
{
ll ans=0,i,j;
scanf("%lld",&n);
K=pow(n,0.66);EU();
for(i=1;i<=n;i=j+1)
{
j=n/(n/i);
ans+=(Gmu(j)-Gmu(i-1))*Gg(n/i)%mod*Gg(n/i)%mod;ans%=mod;
}
printf("%lld",(ans+mod)%mod);
}
另附 求 做法,實測並快不了多少,但如果是算單個應該快很多。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
#define N 12345678
#define ll long long
using namespace std;
const ll mod=1e9+7;
map<ll,ll>Mu,G;
ll n,K,tot,P[N],g[N],mu[N],pc[N],pd[N];
void EU()
{
ll i,j;mu[1]=g[1]=1;
for(i=2;i<=K;i++)
{
if(!g[i])P[++tot]=i,mu[i]=-1,g[i]=2,pc[i]=1,pd[i]=tot;
for(j=1;j<=tot&&i*P[j]<=K;j++)
{
if(i%P[j])
{
pc[i*P[j]]=1;
pd[i*P[j]]=j;
mu[i*P[j]]=-mu[i];
g[i*P[j]]=g[i]<<1;
}
else
{
pc[i*P[j]]=j==pd[i]?pc[i]+1:1;
pd[i*P[j]]=j;
g[i*P[j]]=j==pd[i]?(g[i]/(pc[i]+1)*(pc[i]+2)):(g[i]<<1);
}
}
}
for(i=2;i<=K;i++)g[i]+=g[i-1],mu[i]+=mu[i-1],g[i]%=mod;
}
ll Gmu(ll x)
{
if(x<=K)return mu[x];
if(Mu[x])return Mu[x];
ll i,j,ans=1;
for(i=2;i<=x;i=j+1)
{
j=x/(x/i);
ans-=(j-i+1)*Gmu(x/i);
}
return Mu[x]=ans;
}
ll Gg(ll x)
{
if(x<=K)return g[x];
if(G[x])return G[x];
ll ans=0,i,j;
for(i=1;i<=x;i=j+1)
{
j=x/(x/i);
ans+=(j-i+1)*(x/i)%mod;ans%=mod;
}
return G[x]=ans;
}
int main()
{
ll ans=0,i,j;
scanf("%lld",&n);
K=pow(n,0.66);EU();
for(i=1;i<=n;i=j+1)
{
j=n/(n/i);
ans+=(Gmu(j)-Gmu(i-1))*Gg(n/i)%mod*Gg(n/i)%mod;ans%=mod;
}
printf("%lld",(ans+mod)%mod);
}