P2257 YY的GCD
Posted tongseli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2257 YY的GCD相关的知识,希望对你有一定的参考价值。
题目描述
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
输入格式
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
输出格式
T行,每行一个整数表示第i组数据的结果
说明/提示
T = 10000
N, M <= 10000000
输入输出样例
输入
2
10 10
100 100
输出
30
2791
这道题类似P3455[POI2007]ZAP-Queries
本题其实是求解
[sumlimits_{pin prime}sumlimits_{x=1}^Nsumlimits_{y=1}^M[gcd(x,y)==p]]
大概就是看见([gcd(x,y)==p]) 就想到([gcd(x,y)==1]) 可以变成(I=mu *u)
[sumlimits_{pin prime}sumlimits_{x=1}^{N/p}sumlimits_{y=1}^{M/p}[gcd(x,y)==1]]
[sumlimits_{pin prime}sumlimits_{x=1}^{N/p}sumlimits_{y=1}^{M/p}sumlimits_{d|gcd(x,y)}mu(d)]
然后整除变枚举
[sumlimits_{pin prime}sumlimits_{x=1}^{N/p}sumlimits_{y=1}^{M/p}sumlimits_{d=1}^{min(N/p,M/p)}mu(d)[d|gcd(x,y)]]
[sumlimits_{pin prime}sumlimits_{d=1}^{min(N/p,M/p)}mu(d)sumlimits_{x=1}^{N/p}sumlimits_{y=1}^{M/p}[d|gcd(x,y)]]
要想(d|gcd(x,y)) ,当且仅当,(d) 同时是 (x,y) 的公因子
(lfloorfrac{N}{d} floor)里有(lfloorfrac{N}{dp} floor)个(d) 的倍数,同理,(lfloorfrac{M}{d} floor)里有(lfloorfrac{M}{dp} floor)个(d) 的倍数
乘法公式,总共就有(lfloorfrac{N}{dp} floorlfloorfrac{M}{dp} floor),就能化简成
[sumlimits_{pin prime}sumlimits_{d=1}^{min(N/p,M/p)}mu(d)lfloorfrac{N}{dp} floorlfloorfrac{M}{dp} floor]
奇思妙想一下,更换一下枚举,(T=dp),就能敲了
[sumlimits_{T=1}^{min(N,M)}lfloorfrac{N}{T} floorlfloorfrac{M}{T} floorsumlimits_{p|T,pin prime}mu(frac{T}{p})]
前面的是分块,后面的是前缀和变形
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7;
int prime[maxn+10];
int vis[maxn+10];
int mu[maxn+10];
int pmu[maxn+10];
ll sum[maxn+10];
void sieve(){
mu[1]=1;
int p=0;
for(int i=2;i<=maxn;i++){
if(!vis[i]){
vis[i]=1;
prime[++p]=i;
mu[i]=-1;
}
for(int j=1;j<=p&&i*prime[j]<=maxn;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=p;i++){
for(int j=1;j*prime[i]<=maxn;j++){
pmu[j*prime[i]]+=mu[j];
}
}
for(int i=1;i<=maxn;i++){
sum[i]=sum[i-1]+(ll)pmu[i];
}
}
int main(){
memset(vis,0,sizeof(vis));
sieve();
int t,n,m;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
ll ans=0;
int t=min(n,m);
int r;
for(int i=1;i<=t;){
r=min(n/(n/i),m/(m/i));
ans+=(ll)(n/i)*(m/i)*(sum[r]-sum[i-1]);
i=r+1;
}
cout<<ans<<endl;
}
}
以上是关于P2257 YY的GCD的主要内容,如果未能解决你的问题,请参考以下文章