51nod 1575 Gcd and Lcm
链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1575
这个题目。完美的体现了洲阁筛更为通用。。。。
题目要就计算:
∑i=1n∑j=1i∑k=1ilcm(gcd(i,j),gcd(i,k))
令 F(n) 有:
F(n)=∑i=1n∑j=1nlcm(gcd(i,n),gcd(j,n))=∑a|n∑b|n∑i=1n∑j=1nabgcd(a,b)[gcd(i,n)=a][gcd(j,n)=b]=∑a|n∑b|nabgcd(a,b)∑i=1na∑j=1nb[i⊥n][j⊥n]=∑a|n∑b|nabgcd(a,b)φ(na)φ(nb)=∑d|n1d∑a|n∑b|nabφ(na)φ(nb)[gcd(a,b)=d]=∑d|nd∑a∣∣∣nd∑b∣∣∣ndabφ(nad)φ(nbd)[a⊥b]=∑d|nnd∑a|d∑b|dabφ(da)φ(db)[a⊥b]
令:
g(n)=g(n,1)g(n,k)=∑a|n∑b|nabφ(na)φ(nb)[gcd(a,b)=k]
令:
G(n,k)=[k|n]∑k|dg(n,d)=[k|n]k2∑a∣∣∣nk∑b∣∣∣nkabφ(nka)φ(nkb)
反演有:
g(n)=g(n,1)=∑d≥1μ(d)d2∑a∣∣∣nd∑b∣∣∣ndabφ(nda)φ(ndb)[d|n]=∑d|nμ(nd)(nd)2∑a|d∑b|dabφ(da)φ(db)=∑d|nμ(nd)(nd)2(∑a|daφ(da))2
因为积性函数的狄利克雷积依然为积性函数。所以 g(n) 为积性函数。
因为 F=N∗g
所以
F
为积性函数:F(Pk)=∑d|PkPkd∑a|d∑b|dabφ(da)φ(db)[a⊥b]=∑x=0kPk−x∑i=0x∑j=0xPi+jφ(Px−i)φ(Px−j)[Pi⊥Pj]=∑x=0kPk−x(2φ(Px)∑j=0x−1Pjφ(Px−j)−φ2(Px)+2Pxφ(Px))=∑x=0kPk−x(2xφ2(Px)−φ2(Px)+2Pxφ(Px))=Pk+∑x=1kPk−x((2x−1)(Px−Px−1)2+2Px(Px−Px−1))=Pk+(Pk−Pk−1)∑x=1k((2x−1)(Px−Px−1)+2Px)
其中:
∑x=1k(2x−1)(Px−Px−1)=∑x=1k(2x−1)Px−∑x=1k(2x−1)Px−1=∑x=1k(2x−1)Px−∑x=0k−1(2x+1)Px=−2∑x=1k−1Px−1+(2k−1)Pk
所以:
Pk+(Pk−Pk−1)∑x=1k((2x−1)(Px−Px−1)+2Px)=Pk+(Pk−Pk−1)(−2∑x=1k−1Px−1+(2k−1)Pk+2∑x=1kPx)=Pk+(Pk−Pk−1)(2Pk+(2k−1)Pk−1)=2(k+1)(P2k−P2k−1)+Pk−1
所以:
F(Pk)=(2k+1)(P2k−P2k−1)+Pk−1
特别的:
F(1)=1
洲阁筛计算之
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <cmath>
#define MAXN 1000000
#define SQR 40000
using namespace std;
typedef unsigned int uint;
const uint INF=0x3f3f3f3f;
uint C0[SQR];
uint _C0[SQR];
uint C1[SQR];
uint _C1[SQR];
uint C2[SQR];
uint _C2[SQR];
uint prim[SQR];
uint pa0[SQR];
uint pa1[SQR];
uint pa2[SQR];
uint F[SQR];
uint _F[SQR];
uint tmp[SQR];
uint Sf[SQR];
uint pf[SQR][32];
bool vis[SQR];
uint S1(uint n)
{
if(n&1)return n*((n+1)>>1);
return (n>>1)*(n+1);
}
uint S2(uint n)
{
uint n1=n+1,n2=2*n+1;
if(n&1)n1>>=1;
else n>>=1;
if(n%3==0)n/=3;
else
{
if(n2%3==0)
n2/=3;
else
n1/=3;
}
return n*n1*n2;
}
uint Pow(uint a,uint b)
{
uint tmp=1;
while(b)
{
if(b&1)
tmp*=a;
a*=a;
b>>=1;
}
return tmp;
}
uint f(uint P,uint c)
{
return (2*c+1)*(Pow(P,c<<1)-Pow(P,(c<<1)-1))+Pow(P,c-1);
}
uint gcd(uint a,uint b)
{
if(b==0)return a;
return gcd(b,a%b);
}
uint FF(uint a,uint b,uint c)
{
uint A=gcd(a,b);
uint B=gcd(a,c);
return A*B/gcd(A,B);
}
int main ()
{
for(uint i=2;i<SQR;i++)
{
pa0[i]=pa0[i-1];
pa1[i]=pa1[i-1];
pa2[i]=pa2[i-1];
Sf[i]=Sf[i-1];
if(vis[i])continue;
prim[++pa0[i]]=i;
pa1[i]+=i;
pa2[i]+=i*i;
Sf[i]+=f(i,1);
for(uint j=1;j<31;j++) pf[i][j]=f(i,j);
for(uint j=i<<1;j<SQR;j+=i)vis[j]=true;
}
uint n,T;
scanf("%u",&T);
while(T--)
{
scanf("%u",&n);
uint m=sqrt(n)+1,V=pow(n,0.25)+1;
for(uint i=1;i<m;i++)
{
C0[i]=i;
_C0[i]=n/i;
C1[i]=C1[i-1]+i;
_C1[i]=S1(n/i);
C2[i]=C2[i-1]+i*i;
_C2[i]=S2(n/i);
}
uint k=1;
while(prim[k]<V)
{
uint P=prim[k];
for(uint i=1;i<m;i++)
{
uint t=i*prim[k];
uint u=n/t;
if(u<m)
{
_C0[i]-=C0[u];
_C1[i]-=C1[u]*P;
_C2[i]-=C2[u]*P*P;
}
else
{
_C0[i]-=_C0[t];
_C1[i]-=_C1[t]*P;
_C2[i]-=_C2[t]*P*P;
}
}
for(uint i=m-1;i;i--)
{
C0[i]-=C0[i/P];
C1[i]-=C1[i/P]*P;
C2[i]-=C2[i/P]*P*P;
}
k++;
}
memset(tmp,0x3f,sizeof tmp);
uint fir,lim=m;
while(prim[k]<m)
{
uint P=prim[k];
fir=lim;
lim=1+n/(prim[k]*prim[k]);
for(uint i=1;i<lim;i++)
{
uint t=P*i;
uint u=n/t;
if(u<m)
{
if(u<prim[k])
{
_C0[i]-=1;
_C1[i]-=P;
_C2[i]-=P*P;
}
else
{
_C0[i]-=pa0[u]-k+2;
_C1[i]-=(pa1[u]-pa1[prim[k-1]]+1)*P;
_C2[i]-=(pa2[u]-pa2[prim[k-1]]+1)*P*P;
}
}
else
{
if(tmp[t]<INF)
{
_C0[i]-=_C0[t]-(k-tmp[t]);
_C1[i]-=P*(_C1[t]-(pa1[prim[k-1]]-pa1[prim[tmp[t]-1]]));
_C2[i]-=P*P*(_C2[t]-(pa2[prim[k-1]]-pa2[prim[tmp[t]-1]]));
}
else
{
_C0[i]-=_C0[t];
_C1[i]-=_C1[t]*P;
_C2[i]-=_C2[t]*P*P;
}
}
}
for(uint i=lim;i<fir;i++)tmp[i]=k;
k++;
}
for(uint i=1;i<m;i++)
{
if(tmp[i]==INF)continue;
_C0[i]-=k-tmp[i];
_C1[i]-=pa1[prim[k-1]]-pa1[prim[tmp[i]-1]];
_C2[i]-=pa2[prim[k-1]]-pa2[prim[tmp[i]-1]];
}
for(uint i=1;i<m;i++)
_F[i]=3*(_C2[i]-_C1[i])+_C0[i];
k--;
V--;
uint X=prim[k];
memset(vis,0,sizeof vis);
while(prim[k]>V)
{
uint P=prim[k];
uint bf;
lim=n/(P*P)+1;
for(uint i=1;i<lim;i++)
{
uint t=i,c=0;
while(t<=n/P)
{
c++;
t*=P;
bf=pf[P][c];
uint u=n/t;
if(u<m)
{
if(u<prim[k])
_F[i]+=bf;
else
_F[i]+=(Sf[u]-Sf[prim[k]]+1)*bf;
}
else
{
if(!vis[t])
_F[i]+=bf*(_F[t]+Sf[X]-Sf[prim[k]]);
else
_F[i]+=bf*_F[t];
}
}
if(!vis[i])
{
_F[i]+=Sf[X]-Sf[prim[k]];
vis[i]=true;
}
}
k--;
}
for(uint i=lim;i<m;i++)_F[i]+=Sf[X]-Sf[prim[k]];
for(uint i=1;i<m;i++)
{
if(i<=V)
F[i]=1;
else
F[i]=Sf[i]-Sf[prim[k]]+1;
}
while(k)
{
uint P=prim[k];
for(uint i=1;i<m;i++)
{
uint d=i,c=0;
while(d<=n/P)
{
d*=P;
c++;
uint u=n/d;
if(u<m)
_F[i]+=F[u]*pf[P][c];
else
_F[i]+=_F[d]*pf[P][c];
}
}
for(uint i=m-1;i;i--)
{
uint d=1,c=0;
while(d*P<=i)
{
d*=P;
c++;
F[i]+=F[i/d]*pf[P][c];
}
}
k--;
}
printf("%u\n",_F[1]);
}
return 0;
}