P1447 [NOI2010]能量采集
首先我们要求的是这个柿子:
\(\displaystyle \sum_{i=1}^{n} \sum_{j=1}^{m} 2 \times gcd(i,j) - 1\)
把 \(2\) 和 \(1\) 提出来,变成:
\(\displaystyle (2 \times \sum_{i=1}^{n} \sum_{j=1}^{m} gcd(i.j)) - n \times m\)
我们主要解决得是这个柿子:
\(\displaystyle \sum_{i=1}^{n}\sum_{j=1}^{m} gcd(i,j)\)
接下来就到了我们的颓柿子的时间啦。
先枚举一个 \(d\) ,变成
\(\displaystyle \sum_{d = 1}^{min(n,m)} d\sum_{i = 1}^{n} \sum_{j=1}^{m} [gcd(i,j) == d]\)
把后面的那两个求和提一个 \(d\) 变成:
\(\displaystyle\sum_{d =1}^{min(n,m)} d \sum_{i=1}^{n\over d}\sum_{j=1}^{m\over d} [gcd(i,j) == 1]\)
然后,我们可以有莫比乌斯反演得到一个柿子:
\([gcd(i,j) == 1] = \displaystyle\sum_{d\mid i,d \mid j} \mu(d)\)
把这个柿子带回去可得
\(\displaystyle\sum_{d=1}^{min(n,m)} d \sum_{i=1}^{n\over d}\sum_{j=1}^{m\over d} \sum_{p\mid i,p\mid j}\mu(p)\)
交换一下求和顺序,先枚举 \(p\) 可得: (注意枚举\(p\) 的上限是 \(min(n,m) \over d\) ,交换一下求和顺序,上限也要改变):
\(\displaystyle\sum_{d=1}^{min(n,m)}d \sum_{p=1}^{min({n\over d},{m\over d})}\mu(p) \sum_{i=1}^{n\over d} [p\mid i] \sum_{j=1}^{m\over d} [p\mid j]\)
因为 \(1- {n\over d}\) 中能被 \(p\) 整除的数有 \(n \over {dp}\) 个,所以后面的枚举 \(i\) 和 \(j\) 的柿子可以改变一下,变成:
\(\displaystyle\sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min({n\over d},{m\over d})}\mu(p) \sum_{i=1}^{n\over dp} \sum_{j=1}^{m\over dp}\)
也就是 :
\(\displaystyle \sum_{d=1}^{min(n,m)} d \sum_{p=1}^{min({n\over d},{m \over d})}\mu(p) \lfloor {n\over dp} \rfloor\lfloor{m \over dp}\rfloor\)
运用一个技巧 ,设 \(Q = d \times p\) ,则 \(p = {Q \over d}\),把所有的 \(p\) 都替换掉,改为枚举 \(Q\),变成:
\(\displaystyle\sum_{d=1}^{min(n,m)}d \sum_{Q=1}^{min(n,m)}\mu({Q\over d}) \lfloor {n \over Q}\rfloor\lfloor{m\over Q}\rfloor\)
至于为什么第二个求和的上限为 \(min(n,m)\),因为 \(p \in{min({n\over d},{m\over d})}\) 则 \(Q\) 的取值范围要在 \(p\) 的基础上乘个 \(d\) 变成 \(min(n,m)\)
交换一下枚举顺序,先枚举一下 \(Q\) 变为
\(\displaystyle\sum_{Q=1}^{min(n,m)}\sum_{d\mid Q}^{min(n,m)} d \times \mu({Q \over d}) \lfloor {n \over Q}\rfloor \lfloor {m \over Q} \rfloor\)
因为 \(\mu\) 的定义域是整数所以 \(Q\over d\) 也需要是整数,也就是 \(Q\mid d\)
后面 可以看成是:
\(\displaystyle\sum_{Q=1}^{min(n,m)}\sum_{d \mid Q}^{min(n,m)}id(d) * \mu({Q\over d})\lfloor{n\over Q}\rfloor\lfloor{m\over Q}\rfloor\)
又因为 \(id * \mu = \phi\), 后面的可以写成卷积的形式,变成:
\(\displaystyle\sum_{Q=1}^{min(n,m)} \phi(Q) \lfloor{n \over Q}\rfloor\lfloor{m \over Q}\rfloor\)
这个我们就可以做到 O(n) 的回答了。
先预处理出 \(\phi\) 函数的值,然后根据上面的柿子计算出答案就可以啦;
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int N = 1e5+10;
int n,m,ans,tot,phi[N],prime[N];
bool check[N];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
void YYCH()//预处理出φ函数的值
{
phi[1] = 1;
for(int i = 2; i <= N-5; i++)
{
if(!check[i])
{
prime[++tot] = i;
phi[i] = i-1;
}
for(int j = 1; j <= tot && i * prime[j] <= N-5; j++)
{
check[i * prime[j]] = 1;
if(i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else
{
phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
}
}
int calc(int d)
{
return (n/d) * (m/d);
}
signed main()
{
n = read(); m = read();
if(n > m) swap(n,m); YYCH();
for(int i = 1; i <= n; i++)
{
ans += phi[i] * calc(i);//计算答案
}
ans = ans * 2 - n * m;
printf("%lld\n",ans);
return 0;
}
Update: 总算写完了这一大堆柿子,累死我了

浙公网安备 33010602011771号