4.10 省选模拟赛 约数 数论 转换 三元组个数
题目很简明 可是 上午反演的时候无计可施。
直接做是nln的 可以简单转换一下 原式=\(\sum_{x=1}^n\frac{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}^n\sum_{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}},y\leq \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;
}