【BZOJ4916】神犇與蒟蒻
阿新 • • 發佈:2018-11-24
題面
Description
很久很久以前,有一隻神犇叫yzy;
很久很久之後,有一隻蒟蒻叫lty;
Input
請你讀入一個整數N;\(1<=N<=10^9\),A、B模\(10^9+7\);
Output
請你輸出一個整數\(A=\sum_{i=1}^N{\mu (i^2)}\);
請你輸出一個整數\(B=\sum_{i=1}^N{\varphi (i^2)}\);
Sample Input
1
Sample Output
1
1
題目分析
第一問:
根據定義,答案永遠等於\(1\)。
第二問:
首先,顯然有\(\varphi(i^2)=i\cdot\varphi(i)\)
根據杜教篩的套路式:
\[ g(1)S(n)=\sum_{i=1}^n(g*f)(i)-\sum_{i=2}^ng(i)S(\frac ni) \]
通過(我也不知道怎麼出來的)分析可得,令\(g(x)=x\):
\[ \begin{split} (f*g)(i)&=\sum_{d|i}\varphi(d)\cdot d\cdot \frac{i}{d}\\ &=\sum_{d|i}\varphi(d)\cdot i\\ &=i\sum_{d|i}\varphi(d)\\ &=i^2 \end{split} \]
如此一來:
\[ \sum_{i=1}^n(g*f)(i)=1^2+2^2+...+n^2=\frac{n\cdot (n+1)\cdot (2\cdot n+1)}6 \]
代回套路式可得:
\[ S(n)=\frac{n\cdot (n+1)\cdot (2\cdot n+1)}6-\sum_{i=2}^ni\cdot S(\frac ni) \]
現在,這個式子就可以用杜教篩解決了。
程式碼實現
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<iomanip> #include<cstdlib> #include<map> #define MAXN 0x7fffffff typedef long long LL; const int N=3e6+5,M=N-5; const int mod=1e9+7,inv6=166666668; using namespace std; inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;} int prime[N],phi[N]; bool vis[N]; map<int,int>sphi; int Sphi(int x){ if(x<=M)return phi[x]; if(sphi[x])return sphi[x]; int ret=1ll*x*(x+1)%mod*(2*x+1)%mod*inv6%mod; for(int l=2,r=0;r!=x;l=r+1){ r=x/(x/l); ret=(ret-1ll*(l+r)*(r-l+1)/2%mod*Sphi(x/l)%mod)%mod; } return sphi[x]=(ret+mod)%mod; } int main(){ phi[1]=1; for(int i=2;i<=M;i++){ if(!vis[i])prime[++prime[0]]=i,phi[i]=i-1; for(int j=1;j<=prime[0]&&1ll*i*prime[j]<=M;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } for(int i=1;i<=M;i++)phi[i]=(1ll*phi[i]*i+phi[i-1])%mod; int n=Getint(); cout<<1<<'\n'<<Sphi(n); return 0; }