题意:
定义f(n)为n所含质因子的最大幂指数。求
∑ni=1∑mj=1f(gcd(i,j))
T<=10000
1<=n,m<=10^7
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#define N 11000000
#define LL long long
using namespace std;
int p[N],pl,a[N],d[N],n,g[N];
LL ans;
bool b[N];
void get_p()
{
for(int i=2;i<N;i++)
{
if(b[i]==0) {p[++pl]=i;a[i]=1;d[i]=i;g[i]=1;}
for(int j=1;j<=pl;j++)
{
if(i*p[j]>=N) break;
b[i*p[j]]=1;
if(i*p[j]==4)
{int oo=1;}
if(i%p[j])
{
a[i*p[j]]=1;d[i*p[j]]=p[j];
if(a[i]!=1) g[i*p[j]]=0;
else g[i*p[j]]=-g[i];
}
else
{
a[i*p[j]]=a[i]+1;d[i*p[j]]=d[i]*p[j];
int t=i/d[i];
if(t==1) g[i*p[j]]=1;
else if(a[t]==a[i*p[j]]) g[i*p[j]]=-g[t];
else g[i*p[j]]=0;
break;
}
}
}
for(int i=1;i<N;i++) g[i]=g[i]+g[i-1];
}
int main()
{
get_p();
int z;scanf("%d",&z);
while(z--)
{
int n,m,nex;scanf("%d%d",&n,&m);
ans=0;
if(n>m) swap(n,m);
for(int i=1;i<=n;i=nex+1)
{
nex=min(n/(n/i),m/(m/i));
ans+=(LL)(n/i)*(m/i)*(g[nex]-g[i-1]);
}
printf("%lld\n",ans);
}
return 0;
}
题解:
先大力化式子
枚举i,j的gcd
∑nd=1f(d)∑ndi=1∑mdj=1ϵ((i,j))
∑nd=1f(d)∑ndi=1∑mdj=1∑k|i,k|jμ(k)
∑nk=1μ(k)∑nkd=1f(d)∑ndki=1∑mdkj=1
枚举D=dk
∑nD=1nDmD∑d|Df(d)μ(Dd)
设
g=f∗μ
∑nD=1nDmDg(D)
算出g后就可以分块解决。
觉得g不是一个积性函数,看了一眼题解(捂脸)“由
μ
和
f
性质可得”
那就大力推一下吧。。
设
k1>=k2>=…>=kt
我们只考虑非0的μ和对应的f
当多个ki值相等的情况,我们把它当作用最小那个i的情况
使f取值为k1,强制p1不选,贡献为
k1∑t−1i=0(−1)iCit−1
k1(1−1)t−1
似乎为0
注意如果对于kj,存在ki>kj,那kj永远不会作为f,因为ki-1>=kj
所以,kj能做f的情况为k1=k2=…=kj且k1到kj-1都被选了
类似,贡献为
(−1)j−1kj∑t−ji=0(−1)iCit−1
(−1)j−1kj(1−1)t−j
如果存在k1=k2=…=kj,kj>kj+1那强制p1到pj都选后,后面所有情况的f依然为k1-1,后面所有情况贡献为
(−1)j(k1−1)∑t−ki=0(−1)iCit−1
(−1)jkj(1−1)t−j
上面所有式子在j不等于t时都为0
唯一不为0的情况就是k1=k2=…=kt时的
(−1)t−1kt(1−1)t−t
以及全部p都被选后的
(−1)t(kt−1)
相加即为
(−1)t+1
于是可以用线性筛求出g。
具体来说就是对于每个数n求出他的最小质因子p最多有k次方,记为a(n)
比较
a(n)和a(npk)
即可从
g(npk)推出g(n)
这是一个递推的关系,用心感受一下就知道很对了。。