卧薪尝胆,厚积薄发。
SDOI2015 约数个数和
Date: Wed Jul 04 08:48:51 CST 2018 In Category: NoCategory

Description:

求: $$ \sum_{i=1}^N\sum_{j=1}^Md(ij) $$ $d(x)$ 为 $x$ 的约数个数

Solution:

$$ \begin{align} &\sum_{i=1}^N\sum_{j=1}^Md(ij)\\ &=\sum_{i=1}^N\sum_{j=1}^M\sum_{i'|i}\sum_{j'|j}[gcd(i',j')==1]\\ &=\sum_{i=1}^N\sum_{j=1}^M\sum_{i'|i}\sum_{j'|j}\sum_{d|i'd|j'}\mu(d) \end{align} $$
交换求和号,得:
$$ \sum\mu(d)\sum_{i=1,d|i}^N\sum_{j=1,d|j}^M\sum_{d|i',i'|i}\sum_{d|j',j'|j}1 $$
再交换,得:
$$ \sum\mu(d)\sum_{d|i‘}\sum_{d|j’}\sum_{i=1,d|i,i'|i}^N\sum_{j=1,d|j,j'|j}^M1 $$
放缩,得:
$$ \sum\mu(d)\sum_{i'=1}^{\lfloor\frac N d\rfloor}\sum_{j’=1}^{\lfloor\frac M d\rfloor}\sum_{i=1,di'|i}^N\sum_{j=1,dj'|j}^M1 $$ 再放缩,得:
$$ \sum_d\mu(d)\sum_{i'=1}^{\lfloor\frac N d\rfloor}\sum_{j’=1}^{\lfloor\frac M d\rfloor}\sum_{i=1}^{\lfloor \frac N {di'}\rfloor}\sum_{j=1}^{\lfloor \frac M {dj'}\rfloor}1\\ =\sum_d\mu(d)\sum_{i'=1}^{\lfloor\frac N d\rfloor}\sum_{j’=1}^{\lfloor\frac M d\rfloor}{\lfloor \frac N {di'}\rfloor}{\lfloor \frac M {dj'}\rfloor}\\ =\sum_d\mu(d)\sum_{i'=1}^{\lfloor\frac N d\rfloor}{\lfloor \frac N {di'}\rfloor}\sum_{j’=1}^{\lfloor\frac{M}{d}\rfloor}{\lfloor \frac M {dj'}\rfloor} $$
由于 $\lfloor\lfloor n/i\rfloor/j\rfloor=\lfloor n/(ij)\rfloor$
故: $$ 原式=\sum\mu(d)\sum_{i'=1}^{\lfloor\frac N d\rfloor}{\lfloor \frac{\lfloor\frac N d \rfloor}{i'}\rfloor}\sum_{j’=1}^{\lfloor\frac M d\rfloor}{\lfloor \frac{\lfloor\frac M d \rfloor}{j'}\rfloor} $$ 设 $\begin{align}g(k)=\sum_{i=1}^k{\lfloor\frac k i\rfloor}\end{align}$ $O(N\sqrt N)$ 预处理 $g$ 。
原式 $\begin{align}=\sum\mu(d)g(\lfloor\frac N d\rfloor)g(\lfloor\frac M d\rfloor)\end{align}$
继续分块即可。

Code:


#include
#include
#include
#include
#include
#include
using namespace std;
int testcases;
#define MAXN 50010
int mu[MAXN],prime[MAXN],tot = 0;
bool isprime[MAXN];
typedef long long ll;
ll g[MAXN],sum[MAXN];
void init()
{
for(int i = 2;i < MAXN;++i)isprime[i] = true;
mu[1] = 1;
for(int i = 2;i < MAXN;++i)
{
if(isprime[i])
{
prime[++tot] = i;
mu[i] = -1;
}
for(int j = 1;j <= tot && i * prime[j] < MAXN;++j)
{
isprime[i * prime[j]] = false;
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = -1 * mu[i];
}
}
}
for(int i = 1;i < MAXN;++i)
{
for(int l = 1,r;l <= i;l = r + 1)
{
r = i / (i / l);
g[i] += (ll)(r - l + 1) * (i / l);
}
sum[i] = sum[i - 1] + mu[i];
}
return;
}
int n,m;
int main()
{
init();
scanf("%d",&testcases);
for(int i = 1;i <= testcases;++i)
{
scanf("%d%d",&n,&m);
if(n > m)swap(n,m);
ll ans = 0;
for(int l = 1,r = 0;l <= n;l = r + 1)
{
r = min(n / (n / l),m / (m / l));
ans += (sum[r] - sum[l - 1]) * g[n / l] * g[m / l];
}
printf("%lld\n",ans);
}

return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡