=== ===
这里放传送门
=== ===
题解
先是喜闻乐见的画柿子阶段(设n为n和m之中较小者):
设 F(d) 为满足 1≤i≤n,1≤j≤m 并且 gcd(i,j)=d 的数字对数, g(d) 为满足 1≤i≤n,1≤j≤m 并且 d|gcd(i,j) 的数字对数
那么关键就是如何对于所有的 T=1..n 求出 h(T)=∑d|Tμ(Td)f(d) 这个东西。可以看出 f(d) 并不是一个积性函数。。但是如果要快速的求出所有需要的 h(T) 好像也只能考虑一下线筛。。如果仍然按照以前的加入质因子的思路来考虑的话,因为 f 函数里面含着一个取
那么我们只能换一个思路来考虑。设 T=pa11∗pa22∗pa33∗...pakk ,选择的因数 d=pb11∗pb22∗pb33∗...pbkk 。显然满足 bi≤ai 。并且还有一个值得注意的地方是有贡献的 bi 应该满足 bi≥ai−1 ,因为式子里面有一个 μ(Td) ,如果 bi 比 ai−1 还要小的话,就会在 Td 里面留下平方项,那么 μ 值就是0,对答案没有贡献。
接下来我们从 Td 的角度来考虑,对于一个质因子 pi ,称 bi=ai−1 的时候为“选择了”这个质因子,相对的, bi=ai 的时候称为“没有选”这个质因子。显然每一种质因子的“选择”方案都唯一对应了一个合法的因数 d 。
因为
那么如果
T
中所有的幂指数
那么只需要在线筛的时候记录最小质因子的指数 e[i] 和去掉最小质因子以后的部分 tmp[i] 就可以了。只要存在 e[i]≠e[tmp[i]] ,要筛的函数值就为0。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,m,prm[10000010],tail,g[10000010],e[10000010];
long long F[10000010],ans;
bool ext[10000010];
void get_prime(int N){
for (int i=2;i<=N;i++){
if (ext[i]==false){
prm[++prm[0]]=i;
F[i]=e[i]=1;g[i]=i;
}
for (int j=1;j<=prm[0];j++){
if ((long long)i*prm[j]>N) break;
ext[i*prm[j]]=true;
if (i%prm[j]==0){
g[i*prm[j]]=g[i]*prm[j];
e[i*prm[j]]=e[i]+1;
int tmp=i/g[i];
if (tmp==1) F[i*prm[j]]=1;
else F[i*prm[j]]=(e[tmp]==e[i*prm[j]])?-F[tmp]:0;
break;
}else{
g[i*prm[j]]=prm[j];
e[i*prm[j]]=1;
F[i*prm[j]]=(e[i]==1)?-F[i]:0;
}
}
}
for (int i=1;i<=N;i++) F[i]+=F[i-1];
}
int main()
{
scanf("%d",&T);
get_prime(10000000);
for (int wer=1;wer<=T;wer++){
scanf("%d%d",&n,&m);ans=0;
if (n>m) swap(n,m);
for (int i=1;i<=n;i=tail+1){
tail=min(n,min(n/(n/i),m/(m/i)));
ans+=(long long)(n/i)*(long long)(m/i)*(F[tail]-F[i-1]);
}
printf("%I64d\n",ans);
}
return 0;
}
偏偏在最后出现的补充说明
这道题在处理与非积性函数相关的线筛的时候用了和以前不同的思路,是一道值得注意的题目

本文介绍了一种处理与非积性函数相关的线性筛选的新思路,通过数学推导和算法实现,解决了特定数学问题,并附带了完整的C++代码。
526

被折叠的 条评论
为什么被折叠?



