51nod 2026 Gcd and Lcm
原题链接
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=2026
题目大意
给你了 f=φ−
计算
∑i=1n∑j=1nf(gcd(i,j))f(lcm(i,j))
f
明显是积性函数。
则:f(gcd(i,j))f(lcm(i,j))=f(gcd(i,j))2f(igcd(i,j))f(jgcd(i,j))=f(i)f(j)
∑i=1n∑j=1nf(i)f(j)=(∑i=1nf(i))2
因为
f=φ−
,所以:
f∗φ∗I=f∗N=e∗I=I
所以直接套用杜教筛有:
Sf(n)=n−∑i=1niSf(⌊ni⌋)
证明: f=φ−
(f∗φ)(n)=∑d|nf(n)φ(nd)=∑d|n∑t|dμ(t)t∑a∣∣∣ndμ(nad)a=∑a|n∑k∣∣∣na∑t∣∣∣nakμ(t)tμ(k)a=∑a|n∑t∣∣∣na∑k∣∣∣natμ(t)tμ(k)a=∑a|n∑t∣∣∣naμ(t)ta∑k∣∣∣natμ(k)当且仅当,at=n时。最右边不为0
则:
∑a|n∑t∣∣∣na且at=nμ(t)ta=n∑a|nμ(na)=[n=1]
所以:
f∗φ=e
证明的过程不断替换固定元素。(如果觉得比较玄学。可以用下面的方法代替)
令
f∗φ=F
F
必然为积性函数。只需要证明F(Pk)=0,k>0 即可
F(Pk)=∑x+y=kf(Px)φ(Py)=∑x+y=k∑i|Pxμ(i)i∑j|Pyμ(j)Pyj=∑y=1k−1(1−P)(Py−Py−1)+1−P+Pk−Pk−1
∑y=1k−1(1−P)(Py−Py−1) 是一个等比数列
∑y=1k−1(1−P)(Py−Py−1)=−(1−P)2(1−Pk−1)1−P=−(1−P)(1−Pk−1)=−1+P−Pk+Pk−1
F(Pk)=−1+P−Pk+Pk−1+1−P+Pk−Pk−1=0
故而:
f∗φ=e
下面是AC代码:
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <map>
#define MAXN 33336
using namespace std;
typedef long long LL;
const int P=1e9+7;
const int P_=P-1;
int Sf[MAXN];
int mu[MAXN]={0,-1};
int m;
struct H
{
struct point
{
int next,key,p;
point(int key,int p,int next):key(key),p(p),next(next){}
point()
{
*this=point(0,0,0);
}
}E[40008];
int A[4000008];
int inof[4000008];
int deep,cnt;
H()
{
cnt=0;
deep=0;
memset(inof,-1,sizeof inof);
}
void add(int x,int key,int S)
{
A[cnt]=S;
E[deep]=point(key,cnt++,inof[x]);
inof[x]=deep++;
}
int find(int key)
{
int d=key%4000007;
for(int i=inof[d];i>-1;i=E[i].next)
{
point &e=E[i];
if(e.key==key)return A[e.p];
}
return -1;
}
void insert(int key,int S)
{
add(key%4000007,key,S);
}
int operator [](const int key)
{
return find(key);
}
}S;
int A(int n)
{
if(n&1)
return (LL)n*((n+1)>>1)%P;
else
return (LL)(n>>1)*(n+1)%P;
}
void slove(int n)
{
int B=sqrt(n)+1;
int ans=0;
for(int L=1;L<B;L++)
{
ans+=(LL)Sf[L]*(A(n/L)-A(n/(L+1))+P)%P;
if(ans>P_)ans-=P;
}
int lim=n/B+1;
for(int i=2;i<lim;i++)
{
int key=n/i;
if(key<MAXN)
ans+=(LL)i*Sf[key]%P;
else
ans+=(LL)i*S[n/i]%P;
if(ans>P_)ans-=P;
}
S.insert(n,(n-ans+P)%P);
}
int main ()
{
for(int i=1;i<MAXN;i++)
{
mu[i]=-mu[i];
for(int j=i<<1;j<MAXN;j+=i)
mu[j]+=mu[i];
}
for(int i=1;i<MAXN;i++)
for(int j=i;j<MAXN;j+=i) Sf[j]+=mu[i]*i;
for(int i=1;i<MAXN;i++)
{
Sf[i]+=Sf[i-1];
if(Sf[i]>P_)Sf[i]-=P;
if(Sf[i]<0)Sf[i]+=P;
}
int n;
scanf("%d",&n);
if(n<MAXN) printf("%d\n",(int)((LL)Sf[n]*Sf[n]%P));
else
{
for(int i=n/MAXN;i>0;i--) slove(n/i);
printf("%d\n",(int)((LL)S[n]*S[n]%P));
}
return 0;
}