这个题推式子还是比较正常的
要推式子 解这种题 需要抓住三个要点:
1、利用约数和倍数关系
2、换Σ
3、乘法优化加法(尽量往 商的值相同合并 上靠)、
注意:处理T的约数d的mu值和时不能用线筛直接求,因为线筛不一定遍历所有约数、
附上一段我的反例:
码:
#include<iostream>
#include<cstdio>
using namespace std;
#include<algorithm>
#include<cstring>
long long mu[10000005],qsum[10000005],su[10000005],tot,i,j,n,m,T;
bool he[10000005];
void eular()
{
mu[1]=1;
// qsum[1]=1;
//memset(qsum,1,sizeof(qsum));
//cout<<qsum[1];
for(i=2;i<=10000000;i++)
{ //qsum[i]++;
if(!he[i])
{
//he[i]=1;
su[++tot]=i;//if(i==7)cout<<"pp";
mu[i]=-1;
// qsum[i]+=mu[1];
}
for(j=1;j<=tot&&su[j]*i<=10000000;j++)
{
he[su[j]*i]=1;
if(i%su[j]==0)
{
mu[i*su[j]]=0;break;
// qsum[i*su[j]]+=mu[i];
// if(!he[i]&&i!=su[j])qsum[i*su[j]]+=mu[su[j]];
}else
{
mu[i*su[j]]=-mu[i];
// qsum[i*su[j]]+=mu[i];
// if(!he[i]&&i!=su[j])qsum[i*su[j]]+=mu[su[j]];
}//if(su[j]*i==42)cout<<su[j]<<" "<<mu[su[j]]<<endl;
}
}
}
long long work(int l,int r)
{
long long ans=0;
long long lin;
if(l>r)swap(l,r);
for(i=1;i<=l;i=lin+1)
{
lin=min(l/(l/i),r/(r/i));
ans+=(qsum[lin]-qsum[i-1])*(l/i)*(r/i);
//cout<<ans<<" "<<i-1<<" ";
}
return ans;
}
int main()
{
eular();
for(i=1;i<=tot;i++)
for(j=1;j*su[i]<=10000000;j++)qsum[j*su[i]]+=mu[j];
for(i=1;i<=10000000;i++)qsum[i]+=qsum[i-1];
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
printf("%lld\n",work(n,m));
}
}