2 条题解
-
0
-
0
问题
给出 (),求$\sum\limits_{i=1}^n\sum\limits_{j=1}^m \lbrack \gcd(i,j)=k \rbrack$
即:满足 ,,且 的二元组 的数量。
题解
$\sum\limits_{i=1}^n\sum\limits_{j=1}^m\lbrack\gcd(i,j)=k\rbrack$ $\sum\limits_{i=1}^{\frac{n}{k}}\sum\limits_{j=1}^{\frac{m}{k}}\lbrack\gcd(i,j)=1\rbrack$ 下来 替换为 $=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d |\gcd(i,j)}\mu(d)$ 注: 变成 是 黄金变换操作。 $\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d=1}^n \lbrack d|i \rbrack \lbrack d|j \rbrack \mu(d)$ 注: 变为 $\sum\limits_{d=1}^n \lbrack d|i \rbrack \lbrack d|j \rbrack \mu(d)$ 是银变换操作。 $=\sum\limits_{d=1}^n \mu(d)\sum\limits_{i=1}^n\lbrack d|i \rbrack \sum\limits_{j=1}^m\lbrack d|j \rbrack$ 注:调换for循环的顺序 $=\sum\limits_{d=1}^n\mu(d) \lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d}\rfloor$ 注: $\sum\limits_{i=1}^n\lbrack d|i \rbrack 变为 \lfloor \frac{n}{d} \rfloor$ 铜变换操作。 到此,在 中 可以前缀和, $\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d}\rfloor$ 可以分块加速即可,从而避免了 逐个枚举 。
具体代码如下:
#include<bits/stdc++.h> #define LL long long using namespace std; const int N=5e4; int pr, p[N+10];LL mu[N+10]; bool v[N+10]; void init() { memset(v,0,sizeof(v)); pr=0;mu[0]=0;mu[1]=1; for(int i=2;i<=N;i++) { if(!v[i]) p[++pr]=i, mu[i]=-1; for(int j=1;j<=pr&&p[j]*i<=N;j++) { v[i*p[j]]=true; if(i%p[j]==0){mu[i*p[j]]=0;break;} mu[i*p[j]]=-mu[i]; } } for(int i=1;i<=N;i++) mu[i]+=mu[i-1]; } LL calc(int n, int m) { if(n>m)swap(n,m); LL ans=0; for(int l=1,r;l<=n;l=r+1) { r=min(n/(n/l), m/(m/l)); ans+=(mu[r]-mu[l-1])*(n/l)*(m/l); } return ans; } int main() { init(); int T,n,m,k;scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); n/=k;m/=k; printf("%lld\n",calc(n,m)); } return 0; }
- 1
信息
- ID
- 2754
- 时间
- 30000ms
- 内存
- 64MiB
- 难度
- 6
- 标签
- 递交数
- 83
- 已通过
- 28
- 上传者