[积性函数]DIVCNT2 - Counting Divisors (square)

http://www.spoj.com/problems/DIVCNT2/

sol:

w(x)表示x的不同的质因子个数
$\sum _{d|{i}^{2}}1=\sum _{d|i}{2}^{w\left(d\right)}$$\sum_{d|i^2}1=\sum_{d|i}2^{w(d)}$实际上就是i的所有约数的质因子的幂是否加上i的对应质因子的幂，这样就成为了i^2的约数了。

$\sum _{d|i}\sum _{q|d}\mu \left(q{\right)}^{2}$$\sum_{d|i}\sum_{q|d} \mu(q)^2$

$1\ast 1\ast {\mu }^{2}$$1*1*\mu^2$
$\left(1\ast 1\right)\ast {\mu }^{2}$$(1*1)*\mu^2$
d(x)表示x的除数函数

$\sum _{i}^{n}\sum _{q|i}\mu \left(q{\right)}^{2}d\left(\frac{i}{q}\right)$$\sum_i^n\sum_{q|i}\mu(q)^2d(\frac iq)$
$\sum _{q}^{n}\mu \left(q{\right)}^{2}\sum _{i}^{\frac{n}{q}}d\left(i\right)$$\sum_q^n\mu(q)^2\sum_i^{\frac nq}d(i)$
2个东西预处理前1e6项，复杂度为$O\left(\frac{2}{3}\right)$$O(\frac 23)$

$\sum _{i}^{\sqrt{d}}\frac{d}{{i}^{2}}\mu \left(i\right)$$\sum_i^\sqrt d \frac d{i^2}\mu(i)$

$\sum _{i}^{n}⌊\frac{n}{i}⌋$$\sum_i^n \lfloor \frac ni \rfloor$

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef double db;
int n,m;
{
char c;
int res,flag=0;
while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
res=c-'0';
while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
return flag?-res:res;
}
const int N=1e6+7;
const int M=1e6;
ll a[N],b[N];
int c[N],prime[N];
bool is[N];
inline ll calc1(int x)
{
if(x<=M) return a[x];
int y=sqrt(x);
ll ans=0;
for(int i=1;i<=y;++i)
ans+=x/i/i*c[i];
return ans;
}
inline ll calc2(int x)
{
if(x<=M) return b[x];
ll ans=0;
int z,zz;
for(int i=1;i<=x;++i)
{
z=x/i;
zz=x/z;
ans+=(zz-i+1)*z;
i=zz;
}
return ans;
}
int main()
{
//  freopen("function.in","r",stdin);
//  freopen("function.out","w",stdout);
n=1000000;
b[1]=1;
for(int i=2;i<=n;++i)
for(int j=1;i*j<=n;++j)
b[i*j]++;
for(int i=2;i<=n;++i)
{
b[i]++;
b[i]=b[i]+b[i-1];
}
c[1]=1;
a[1]=1;
for(int i=2;i<=n;++i)
{
if(!is[i]) prime[++prime[0]]=i,c[i]=-1;
for(int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
{
is[i*prime[j]]=1;
if(!(i%prime[j]))
{
c[i*prime[j]]=0;
break;
}
c[i*prime[j]]=-c[i];
}
a[i]=a[i-1]+(c[i]!=0);
}
while(m--)
{
int z,zz;
ll ans=0;
for(int i=1;i<=n;++i)
{
z=n/i;
zz=n/z;
ans+=(calc1(zz)-calc1(i-1))*calc2(z);
i=zz;
}
printf("%lld\n",ans);
}
}


• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120