输入1:
23
输入2:
77685
输出1:
18690
输出2:
1200366582
这多久以前了。
好像才两天前……
反正比赛时看到lcm,看到gcd就以为是什么神奇的莫比乌斯函数。
虾鸡儿乱搞,发现我还是不能把里面的gcd给挖出来。
然后再大力尝试改变枚举位置,反正最后划出来的式子奇丑无比。
然鹅我还天真地以为数据是根号级别的。
其实是min25版题(并不)
太菜了。
吭哧吭哧一天终于再次搞懂了min25,然后吭哧吭哧一天终于把这道题的毒瘤式子推出来了。
心力憔悴
首先回顾min25的几个要点,首先是积性函数。
这个东东直接感受一下就好了,毕竟不是完全积性函数,然后又是求gcd,所以直接相乘并不会多出些奇怪的东东。
其次是 f ( p q ) f(p^q) f(pq)能快速求,且 f ( p ) f(p) f(p)能表示成多项式或几个完全积性函数的积。
这个东东并不显然,我们直接推柿子。
先有一个引理,之后会用到:
l c m ( g c d ( a , b ) , g c d ( a , c ) ) = g c d ( a , l c m ( b , c ) ) lcm(gcd(a,b),gcd(a,c))=gcd(a,lcm(b,c)) lcm(gcd(a,b),gcd(a,c))=gcd(a,lcm(b,c))
引理证明:
考虑gcd和lcm的意义是什么。我们发现,对于任意两个数a,b分解质因数,那么他们之间的gcd和lcm即为质因数指数求min和求max。
那么上柿子我们就变为:
m a x ( m i n ( a ′ , b ′ ) , m i n ( a ′ , c ′ ) ) = m i n ( a ′ , m a x ( b ′ , c ′ ) ) max(min(a',b'),min(a',c'))=min(a',max(b',c')) max(min(a′,b′),min(a′,c′))=min(a′,max(b′,c′))
其中 a ′ , b ′ , c ′ a',b',c' a′,b′,c′意义是分解质因数后 a , b , c a,b,c a,b,c同一个质数的指数是多少。
然后这个东东分类讨论即可知道他是对的。
当然,换成另一个形式也是正确的:
g c d ( l c m ( a , b ) , l c m ( a , c ) ) = l c m ( a , g c d ( b , c ) ) gcd(lcm(a,b),lcm(a,c))=lcm(a,gcd(b,c)) gcd(lcm(a,b),lcm(a,c))=lcm(a,gcd(b,c))
现在正式开始推柿子。
∑ i = 1 n ∑ j = 1 i ∑ k = 1 i l c m ( g c d ( i , j ) , g c d ( i , k ) ) \sum_{i=1}^n\sum_{j=1}^i\sum_{k=1}^ilcm(gcd(i,j),gcd(i,k)) i=1∑nj=1∑ik=1∑ilcm(gcd(i,j),gcd(i,k))
我们用一个函数替换后面的东东:
∑ i = 1 n f ( i ) , f ( x ) = ∑ j = 1 x ∑ k = 1 x l c m ( g c d ( x , j ) , g c d ( x , k ) ) \sum_{i=1}^nf(i),f(x)=\sum_{j=1}^x\sum_{k=1}^xlcm(gcd(x,j),gcd(x,k)) i=1∑nf(i),f(x)=j=1∑xk=1∑xlcm(gcd(x,j),gcd(x,k))
现在问题变为求f。
f ( p q ) = ∑ j = 1 p q ∑ k = 1 p q l c m ( g c d ( p q , j ) , g c d ( p q , k ) ) f(p^q)=\sum_{j=1}^{p^q}\sum_{k=1}^{p^q}lcm(gcd(p^q,j),gcd(p^q,k)) f(pq)=j=1∑pqk=1∑pqlcm(gcd(pq,j),gcd(pq,k))
= ∑ i = 0 q p i ∑ j = 1 p q ∑ k = 1 p q [ l c m ( g c d ( p q , j ) , g c d ( p q , k ) ) = p i ] =\sum_{i=0}^qp^i\sum_{j=1}^{p^q}\sum_{k=1}^{p^q}[lcm(gcd(p^q,j),gcd(p^q,k))=p^i] =i=0∑qpij=1∑pqk=1∑pq[lcm(gcd(pq,j),gcd(pq,k))=pi]
= ∑ i = 0 q p i ∑ j = 1 p q ∑ k = 1 p q [ g c d ( p q , l c m ( j , k ) ) = p i ] =\sum_{i=0}^qp^i\sum_{j=1}^{p^q}\sum_{k=1}^{p^q}[gcd(p^q,lcm(j,k))=p^i] =i=0∑qpij=1∑pqk=1∑pq[gcd(pq,lcm(j,k))=pi]
已知,c>q,那么可以从gcd的意义上知道,柿子可以拆成这样:
= ∑ i = 0 q p i ∑ j = 1 p q ∑ k = 1 p q [ l c m ( j , k ) = s ∗ p i 且 s ! ∣ p ( 不 整 除 ) ] =\sum_{i=0}^qp^i\sum_{j=1}^{p^q}\sum_{k=1}^{p^q}[lcm(j,k)=s*p^i且s !| p(不整除)] =i=0∑qpij=1∑pqk=1∑pq[lcm(j,k)=s∗pi且s!∣p(不整除)]
然后这样还是很难直接推,于是继续从意义下手。
首先,右边的 s p i sp^i spi(sp杂化现象) 可以拆成两部分,一个是 s s s,一个是 p i p^i pi,所以我们分开贡献算。我们考虑 j j j的贡献为 p x ∗ s 1 p^x*s1 px∗s1, k k k的贡献为 p y ∗ s 2 p^y*s2 py∗s2。那么我们可以知道,那个s我们可以直接用欧拉函数来表示,然后再注意一下边界即可得到下面柿子:
φ ( p q − i ) 2 + 2 ∗ ∑ x = 0 i − 1 φ ( p q − x ) ∗ φ ( p q − i ) \varphi (p^{q-i})^2+2*\sum_{x=0}^{i-1}\varphi (p^{q-x})*\varphi (p^{q-i}) φ(pq−i)2+2∗x=0∑i−1φ(pq−x)∗φ(pq−i)
然后再利用等比数列和欧拉函数的性质,大力地花费多张草稿纸和理智和心智,即可将这个丑陋的式子拆掉。
(mdzz推了我两次错的,正负号看得昏头)
所以我们终于得到一个非常好康的式子:
f ( p q ) = ( 2 q + 1 ) ∗ ( p 2 q − p 2 q − 1 ) + p q − 1 f(p^q)=(2q+1)*(p^{2q}-p^{2q-1})+p^{q-1} f(pq)=(2q+1)∗(p2q−p2q−1)+pq−1
所以我们就满足min25的几个条件了。
切吧!
注意着玩意还要自然溢出,帮pascal选手 (话说还有这玩意儿吗) QWQ。
#include
#include
#include
#include
using namespace std;
const unsigned long long mo=4294967296;
const int maxn=1000010;
unsigned long long zs[maxn],n,m,d[maxn],sum[maxn],sum1[maxn],id,wz1,wz2,id1[maxn],id2[maxn],g2[maxn],g1[maxn],g0[maxn],nex,now;
int tot;
bool bz[maxn];
unsigned long long qsm(unsigned long long a,unsigned long long b)
{
unsigned long long t=1;
unsigned long long y=a;
while (b>0)
{
if ((b&1)==1) t=t*y%mo;
y=y*y%mo;
b/=2;
}
return t;
}
void getg()
{
for (int i=1;i<=zs[0];i++)
{
for (int j=1;j<=tot;j++)
{
if (zs[i]*zs[i]<=d[j])
{
id=d[j]/zs[i];
if (id<=m) wz1=id1[id];else wz1=id2[n/id];
id=zs[i]-1;
if (id<=m) wz2=id1[id];else wz2=id2[n/id];
g2[j]=(g2[j]-zs[i]*zs[i]%mo*(g2[wz1]-sum1[i-1]+mo)%mo+mo)%mo;
g1[j]=(g1[j]-zs[i]%mo*((g1[wz1]-sum[i-1]+mo)%mo)%mo+mo)%mo;
g0[j]=(g0[j]-(g0[wz1]-(i-1))%mo+mo)%mo;
}
else
{
break;
}
}
}
}
long long js(long long p,long long q)
{
unsigned long long a=(q*2%mo+1)%mo;
unsigned long long b=(qsm(p,2*q)-qsm(p,2*q-1)+mo)%mo;
unsigned long long c=(qsm(p,q-1))%mo;
return (a*b%mo+c)%mo;
}
unsigned long long gets(unsigned long long a,int b)
{
if (a==0 || zs[b]>a) return 0;
// printf("%lld\n",a);
unsigned long long id=a,wz1,wz2;
if (id<=m) wz1=id1[id]; else wz1=id2[n/id];
long long ss=0;
ss=((3*g2[wz1]%mo-3*g1[wz1]%mo+g0[wz1]+mo)%mo-(3*sum1[b-1]%mo-3*sum[b-1]%mo+(b-1)+mo)%mo+mo)%mo;
for (int i=b;i<=zs[0];i++)
{
if (zs[i]*zs[i]<=a)
{
unsigned long long mi=zs[i];
if (zs[i]*zs[i]>a) continue;
for (int e=1;mi*zs[i]<=a;e++,mi=mi*zs[i])
{
unsigned long long kk1=js(zs[i],e);
unsigned long long kk2=js(zs[i],e+1);
ss=(ss+kk1*gets(a/mi,i+1)%mo+kk2%mo)%mo;
}
}
else break;
}
return ss;
}
int main()
{
freopen("data.in","r",stdin);
// freopen("sum.in","r",stdin);
// freopen("sum.out","w",stdout);
for (int i=2;i<=100000;i++)
{
if (!bz[i])
{
zs[0]++;
zs[zs[0]]=i;
for (int j=1;j<=100000/i;j++)
{
bz[j*i]=true;
}
}
}
for (int i=1;i<=zs[0];i++)
{
sum[i]=(sum[i-1]+zs[i]%mo)%mo;
sum1[i]=(sum1[i-1]+zs[i]*zs[i]%mo)%mo;
}
scanf("%lld",&n);
if (n==1)
{
printf("1\n");
return 0;
}
m=sqrt(n);
for (long long i=1;i<=n;i=nex+1)
{
if (i>100000)
{
int j=0;
}
nex=n/(n/i);
d[++tot]=n/i;
now=(n/i);
unsigned long long op1=now;
unsigned long long op2=now+1;
unsigned long long op3=2*now+1;
if (op1%2==0) op1/=2;
else if (op2%2==0) op2/=2;
else if (op3%2==0) op3/=2;
if (op1%3==0) op1/=3;
else if (op2%3==0) op2/=3;
else if (op3%3==0) op3/=3;
g2[tot]=(op1%mo*op2%mo*op3%mo+mo-1)%mo;
op1=now;
op2=now+1;
if (op1%2==0) op1/=2;
else if (op2%2==0) op2/=2;
g1[tot]=(op1%mo*op2%mo-1+mo)%mo;
g0[tot]=(now-1+mo)%mo;
if (d[tot]<=m) id1[n/i]=tot;
else id2[n/(n/i)]=tot;
}
getg();
unsigned long long ans=gets(n,1);
printf("%u\n",(ans+1)%mo);
}