问题:查找
到目前为止我使用的方法:
蛮力
while(Q--)
{
int N;
cin>>N;
for(int i=1;i<=N;i++)
ans += lcm(i,N)/i ;
}
首先,我建立一个表,其中包含每个 N 的欧拉函数值。这可以在 O(N) 中完成。
void sieve()
{
// phi table holds euler totient function value
// lp holds the lowest prime factor for a number
// pr is a vector which contains prime numbers
phi[1]=1;
for(int i=2;i<=MAX;i++)
{
if(lp[i]==0)
{
lp[i]=i;
phi[i]=i-1;
pr.push_back(i);
}
else
{
if(lp[i]==lp[i/lp[i]])
phi[i] = phi[i/lp[i]]*lp[i];
else phi[i] = phi[i/lp[i]]*(lp[i]-1);
}
for(int j=0;j<(int)pr.size()&&pr[j]<=lp[i]&&i*pr[j]<=MAX;j++)
lp[i*pr[j]] = pr[j];
}
对于每个查询,分解 N 并添加d*phi[d]
到结果中。
for(int i=1;i*i<=n;i++)
{
if(n%i==0)
{
// i is a factor
sum += (n/i)*phi[n/i];
if(i*i!=n)
{
// n/i is a factor too
sum += i*phi[i];
}
}
}
这需要 O(sqrt(N)) 。
复杂度:O(Q*sqrt(N))
在 O(1) 中处理查询
在我上面描述的筛法中,我添加了一个计算我们在 O(NLogN) 中需要的答案的部分
for(int i=1;i<=MAX;++i)
{
//MAX is 10^7
for(int j=i;j<=MAX;j+=i)
{
ans[j] += i*phi[i];
}
}
不幸的是,对于给定的约束和时间限制(1 秒),这会超时。
我认为这涉及到关于 N 的素数分解的一些聪明的想法。我可以使用上面构建的 lp(lowest prime) 表对 O(LogN) 中的一个数字进行素数因式分解,但我无法弄清楚如何使用因式分解得出答案。