AmazingCounters.com

[BZOJ]2820: YY的GCD

Time Limit: 10 Sec  Memory Limit: 512 MB

Description

  神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种傻×必然不会了,于是向你来请教……多组输入

Input

  第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M

Output

  T行,每行一个整数表示第i组数据的结果

Sample Input

  2
  10 10
  100 100

Sample Output

  30
  2791

HINT

  T = 10000
  N, M <= 10000000

Solution

  枚举质数p,答案即为$\sum_{p}\sum_{i=1}^{\left \lfloor n/p \right \rfloor}\sum_{j=1}^{\left \lfloor m/p \right \rfloor}\left [  gcd(i,j)=1\right ]=\sum_{p}\sum_{i=1}^{\left \lfloor n/p \right \rfloor}\sum_{j=1}^{\left \lfloor m/p \right \rfloor}\sum_{d|i,d|j}\mu (d)$

  考虑每个d,则原式等于$\sum_{p}\sum_{d=1}^{\left\lfloor min(n,m)/p \right\rfloor}\left\lfloor \frac{n}{pd} \right\rfloor \left\lfloor \frac{m}{pd} \right\rfloor \mu (d)$

  令k=pd,得到$\sum_{k=1}^{min(n,m)}\left\lfloor \frac{n}{k} \right\rfloor \left\lfloor \frac{m}{k} \right\rfloor \sum_{p|k}\mu(\frac{k}{p})$

  用筛法可以预处理出每个k对应的$\sum_{p|k}\mu(\frac{k}{p})$,前缀和后利用$\left\lfloor \frac{n}{k} \right\rfloor \left\lfloor \frac{m}{k} \right\rfloor$只有$O(\sqrt{n})$种取值,我们可以在$O(\sqrt{n})$的时间内计算每次询问,总复杂度$O(n+T\sqrt{n})$。

Code

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
    return x;
}
#define MN 10000000
int mu[MN+5],p[MN+5],pn;
ll f[MN+5];
bool u[MN+5];
int main()
{
    int T=read(),n,m,i,j;ll ans;
    for(mu[1]=1,i=2;i<=MN;++i)
    {
        if(!u[i])p[++pn]=i,mu[i]=-1;
        for(j=1;i*p[j]<=MN&&(u[i*p[j]]=1);++j)
            if(i%p[j])mu[i*p[j]]=-mu[i];else break;
    }
    for(i=1;i<=pn;++i)for(j=1;j*p[i]<=MN;++j)f[j*p[i]]+=mu[j];
    for(i=1;i<=MN;++i)f[i]+=f[i-1];
    while(T--)
    {
        n=read();m=read();ans=0;
        for(i=1;i<=n&&i<=m;i=j+1)j=min(n/(n/i),m/(m/i)),ans+=(f[j]-f[i-1])*(n/i)*(m/i);
        printf("%lld\n",ans);
    }
}
posted on 2017-04-05 09:07  ditoly  阅读(328)  评论(0编辑  收藏  举报