码迷,mamicode.com
首页 > 其他好文 > 详细

P2257 YY的GCD

时间:2019-10-11 12:47:39      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:class   提示   limit   gcd   bit   scan   clu   line   质数   

题目描述

神犇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

本题其实是求解

\[\sum\limits_{p\in prime}\sum\limits_{x=1}^N\sum\limits_{y=1}^M[\gcd(x,y)==p]\]

大概就是看见\([\gcd(x,y)==p]\) 就想到\([\gcd(x,y)==1]\) 可以变成\(I=\mu *u\)

\[\sum\limits_{p\in prime}\sum\limits_{x=1}^{N/p}\sum\limits_{y=1}^{M/p}[\gcd(x,y)==1]\]

\[\sum\limits_{p\in prime}\sum\limits_{x=1}^{N/p}\sum\limits_{y=1}^{M/p}\sum\limits_{d|\gcd(x,y)}\mu(d)\]

然后整除变枚举

\[\sum\limits_{p\in prime}\sum\limits_{x=1}^{N/p}\sum\limits_{y=1}^{M/p}\sum\limits_{d=1}^{\min(N/p,M/p)}\mu(d)[d|\gcd(x,y)]\]

\[\sum\limits_{p\in prime}\sum\limits_{d=1}^{\min(N/p,M/p)}\mu(d)\sum\limits_{x=1}^{N/p}\sum\limits_{y=1}^{M/p}[d|\gcd(x,y)]\]

要想\(d|\gcd(x,y)\) ,当且仅当,\(d\) 同时是 \(x,y\) 的公因子

\(\lfloor\frac{N}{d}\rfloor\)里有\(\lfloor\frac{N}{dp}\rfloor\)\(d\) 的倍数,同理,\(\lfloor\frac{M}{d}\rfloor\)里有\(\lfloor\frac{M}{dp}\rfloor\)\(d\) 的倍数

乘法公式,总共就有\(\lfloor\frac{N}{dp}\rfloor\lfloor\frac{M}{dp}\rfloor\),就能化简成

\[\sum\limits_{p\in prime}\sum\limits_{d=1}^{\min(N/p,M/p)}\mu(d)\lfloor\frac{N}{dp}\rfloor\lfloor\frac{M}{dp}\rfloor\]

奇思妙想一下,更换一下枚举,\(T=dp\),就能敲了

\[\sum\limits_{T=1}^{\min(N,M)}\lfloor\frac{N}{T}\rfloor\lfloor\frac{M}{T}\rfloor\sum\limits_{p|T,p\in 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

标签:class   提示   limit   gcd   bit   scan   clu   line   质数   

原文地址:https://www.cnblogs.com/tongseli/p/11653238.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!