版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/85036860
题目描述:
求
其中
表示约数个数,
,时间限制20s
题目分析:
其中,
表示
的质因子个数,上式可以理解为从i中选出一些质因子,每个质因子可以取当前次幂或者加上最高次幂两种选择。
可看出
为d的无平方因子个数,所以
整理一下,记
,那么
所以
显然需要处理
和
的前缀和
线性筛五千万到一亿(少了会TLE),剩下的可以这么算:
- 从"
以内无平方因子数的个数"的意义出发,考虑容斥,可以得出:
计算 - 约数个数的前缀和很好算:
分块计算
与杜教筛的时间复杂度分析类似,总时间
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 50000000;
int p[N/10],mu[N+5],sd[N+5],sm[N+5];
bool v[N+5];
void Prime(int N)
{
mu[1]=sd[1]=sm[1]=1;int cnt=0;
for(int i=2;i<=N;i++)
{
if(!v[i]) p[++cnt]=i,mu[i]=-1,sm[i]=sd[i]=2;//sm now replace ak to use
for(int j=1,k;j<=cnt&&p[j]*i<=N;j++)
{
v[k=p[j]*i]=1;
if(i%p[j]==0) {mu[k]=0,sd[k]=sd[i]/sm[i]*(sm[i]+1),sm[k]=sm[i]+1;break;}
mu[k]=-mu[i],sd[k]=sd[i]*sd[p[j]],sm[k]=2;
}
}
for(int i=1;i<=N;i++) sd[i]+=sd[i-1],sm[i]=sm[i-1]+abs(mu[i]);
}
LL Summu(LL n)
{
if(n<=N) return sm[n];
LL ret=0;
for(LL i=1;i*i<=n;i++) ret+=mu[i]*n/(i*i);
return ret;
}
LL Sumd(LL n)
{
if(n<=N) return sd[n];
LL ret=0;
for(LL i=1,j;i<=n;i=j+1)
{
j=n/(n/i);
ret+=(j-i+1)*(n/i);
}
return ret;
}
LL solve(LL n)
{
LL ans=0;
for(LL i=1,j,pre=0,tmp;i<=n;i=j+1)
{
j=n/(n/i);
tmp=Summu(j);
ans=ans+Sumd(n/i)*(tmp-pre);
pre=tmp;
}
return ans;
}
int main()
{
LL n[10005];int T;
scanf("%d",&T);
for(int i=1;i<=T;i++) scanf("%lld",&n[i]);
if(*max_element(n+1,n+1+T)<=10000) Prime(10000);
else Prime(N);
for(int i=1;i<=T;i++) printf("%lld\n",solve(n[i]));
}