题目很简明 可是 上午反演的时候无计可施。
直接做是nln的 可以简单转换一下 原式=(sum_{x=1}^nfrac{n}{x}d(x))
这样就有一个O(n)的做法了 由于d是积性函数直接筛就好了。没必要整除分块 直接O(n).
const int MAXN=15000010;
int n,top;
int v[MAXN],g[MAXN],p[1000010],d[MAXN];
inline void prepare()
{
d[1]=1;
rep(2,n,i)
{
if(!v[i])
{
p[++top]=g[i]=v[i]=i;
ll sum=p[top];int j=1;
while(sum<=n)d[sum]=j+1,sum=sum*p[top],++j;
}
rep(1,top,j)
{
if(n/i<p[j])break;
int ww=i*p[j];
v[ww]=p[j];
if(p[j]==v[i])
{
g[ww]=g[i]*p[j];
d[ww]=d[i/g[i]]*d[g[ww]];
break;
}
d[ww]=d[i]*d[p[j]];
g[ww]=p[j];
}
}
}
int main()
{
//freopen("divisor.in","r",stdin);
//freopen("divisor.out","w",stdout);
get(n);
if(n<=15000000)
{
prepare();//put(top);
//rep(1,n,i)put(d[i]);
ll sum=0;
rep(1,n,i)sum=sum+(ll)(n/i)*d[i];
putl(sum);
}
return 0;
}
推到这里就可以自闭了。
d这个函数的前缀和不能杜教筛 也没有一个gcd的东西可以代替 如(d(i)=sum_{x=1}^{i}[(x,i)=x])这个东西没啥用 还是很难化简。
还要一个 (d(xy)=sum_{i|x}^{x}sum_{j|y}^{y}[(i,j)=1])
都跟本题没啥关系。
这道题之所以能做是因为 求的是前缀和这个特异性问题。
(d(w)=sum_{x|w}1) 观察这个东西可以发现(x,frac{w}{x})这个东西是一个二元组。
而(sum_{i=1}^nsum_{p|i}d(p))观察这个东西 对于一个i来说 有(frac{i}{p},d(p))即(frac{i}{p},frac{w}{x},x)
这个三元组会对答案贡献1.
可以发现 对于所有的三元组 xyz<=n 这样的三元组都会被计数。
且这个三元组是唯一存在于一个数字i内的。
设x<=y<=z.若x<=(n^{frac{1}{3}},yleq sqrt(frac{n}{x}))
枚举x,y统计z的数量即可。
由于x,y,z可以是一个排列所以要乘6.
但是观察上面的三元组的情况 发现对于x==y的时候这种情况是没有排列的所以需要减掉相应的次数 三个数字相等也同理。
非常妙的一道题。至于复杂度接近于(n^{frac{2}{3}})(我也不会证明。
const ll MAXN=100010;
ll n;
int main()
{
freopen("divisor.in","r",stdin);
freopen("divisor.out","w",stdout);
get(n);
ll w1=1,w2=1,ans=0;
while(w1*w1*w1<=n)++w1;--w1;
while(pf(w2)<=n)++w2;--w2;
for(ll i=1;i<=w1;++i)
{
ll ww=n/i;
for(ll j=i;j*j<=ww;++j)ans+=ww/j-j+1;
}
ll cnt=0;
for(ll i=1;i<=w2;++i)cnt+=n/i/i;
putl(ans*6-cnt*3-2*w1);
return 0;
}