问题:查找
主要挑战是处理可能很大的查询(Q)。 1< = Q< =
到目前为止我使用的方法:
暴力
while(Q--)
{
int N;
cin>>N;
for(int i=1;i<=N;i++)
ans += lcm(i,N)/i ;
}
中的查询
首先,我构建一个表,其中包含每个N的euler totient函数的值。 这可以在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(最低素数)表来对O(LogN)中的数字进行分解,但我无法弄清楚如何使用因子分解得出答案。
答案 0 :(得分:0)
您可以尝试以下算法:
lcm(i,n) / i = i * n / i * gcd(i, n) = n / gcd(i, n)
现在应该找到数字n / gcd(i, n)
的总和。
让n = p1^i1 * p2^i2 * p3^j3
号p1, p2, ... pk
为素数。
n / gdc(i, n)
为gcd(i , n) == 1
的项目数phi[n] = n*(p1-1)*(p2-1)*...*(pk-1)/(p1*p2*...*pk)
,因此添加到总和n*phi[n]
。
n / gdc(i, n)
为gcd(i , n) == p1
的项目数phi[n/p1] = (n/p1)*(p1-1)*(p2-1)*...*(pk-1)/(p1*p2*...*pk)
,因此添加到总和n/p1*phi[n/p1]
。
n / gdc(i, n)
为gcd(i , n) == p1*p2
的项目数phi[n/(p1*p2)] = (n/(p1*p2))*(p1-1)*(p2-1)*...*(pk-1)/(p1*p2*...*pk)
,因此添加到总和n/(p1*p2)*phi[n/(p1*p2)]
。
现在回答是总和
n/(p1^j1*p2^j2*...*pk^jk) phi[n/(p1^j1*p2^j2*...*pk^jk)]
全部
j1=0,...,i1
j2=0,...,i2
....
jk=0,...,ik
此总和中的项目总数为i1*i2*...*ik
,远小于O(n)。
要计算此总和,您可以使用具有自由参数初始编号,当前表示和初始表示的递归函数:
initial = {p1:i1, p2:i2, ... ,pn:in}
current = {p1:i1, p2:i2, ... ,pn:in}
visited = {}
int calc(n, initial, current, visited):
if(current in visited):
return 0
visited add current
int sum = 0
for pj in keys of current:
if current[pj] == 0:
continue
current[pj]--
sum += calc(n, initial, current)
current[pj]++
mult1 = n
for pj in keys of current:
mult1 /= pj^current[pj]
mult2 = mult1
for pj in keys of current:
if initial[pj] == current[pj]:
continue
mult2 = mult2*(pj -1)/pj
sum += milt1 * mult2
return sum