1. 程式人生 > >bzoj 4176: Lucas的數論 -- 杜教篩,莫比烏斯反演

bzoj 4176: Lucas的數論 -- 杜教篩,莫比烏斯反演

i++ define hint .net width long .com cas string

4176: Lucas的數論

Time Limit: 30 Sec Memory Limit: 256 MB

Description

去年的Lucas非常喜歡數論題,但是一年以後的Lucas卻不那麽喜歡了。

在整理以前的試題時,發現了這樣一道題目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的約數個數。他現在長大了,題目也變難了。 求如下表達式的值: 技術分享圖片 其中 表示ij的約數個數。 他發現答案有點大,只需要輸出模1000000007的值。

Input

第一行一個整數n。

Output

一行一個整數ans,表示答案模1000000007的值。

Sample Input

2

Sample Output

8

HINT

對於100%的數據n <= 10^9。

Source

emmmm,轉載一份題解吧,寫的很清晰了 http://blog.csdn.net/clove_unique/article/details/67633389

我們先反演一下,化簡成這樣

技術分享圖片

然後就括號內的東西可以O(√n)算出,然後杜教篩出mu值,就可以了

(復雜度不要問我qwq

#include<map>
#include<cmath>
#include<queue>
#include
<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define mod 1000000007 #define ll long long #define N 1000555 int mu[N],pri[N],tot; bool vs[N]; void INIT() { mu[1]=1; for(int i=2;i<N;i++) { if(!vs[i]) pri[++tot]=i,mu[i]=-1
; for(int j=1;j<=tot&&pri[j]*i<N;j++) { vs[pri[j]*i]=1; if(i%pri[j]==0){mu[pri[j]*i]=0;break;} mu[pri[j]*i]=-mu[i]; } mu[i]+=mu[i-1]; } } int n; ll ans; ll F(int x) { ll tp=0; for(int i=1,j;i<=x;i=j+1) { j=x/(x/i); (tp+=(ll)(x/i)*(j-i+1))%=mod; } return tp*tp%mod; } map<int,int>p; ll sol(int x) { if(x<N) return mu[x]; if(p[x]) return p[x]; ll ta=1; for(int i=2,j;i<=x;i=j+1) { j=x/(x/i); (ta-=sol(x/i)*(j-i+1))%=mod; } if(ta<0) ta+=mod; return p[x]=ta; } int main() { INIT(); scanf("%d",&n); for(int i=1,j;i<=n;i=j+1) { j=n/(n/i); (ans+=F(n/i)*(sol(j)-sol(i-1)+mod))%=mod; } printf("%lld\n",ans); return 0; }

bzoj 4176: Lucas的數論 -- 杜教篩,莫比烏斯反演