SPOJ 4491 Primes in GCD Table

来源:互联网 发布:中文可以编程吗 编辑:程序博客网 时间:2024/05/18 16:57

题目链接:Primes in GCD Table

题目大意:这道题跟BZOJ2820是一样的,不过没有权限号,就上SPOJ交去了,实际上题目就是给你n,m求1<=x<=N, 1<=y<=M且gcd(x,y)为质数有多少对

题思路:如果gcd(x,y)这个质数给定了,是不是就很好求,然后我们想到可以去枚举这些素数,然后运算(T成傻逼)这个时候我们需要简化一点运算,我们可以先反演出这个公式没问题f(x)=x|dμ(dx)ndmd
再令x=p,d=pi
然后可得ans=nisprime(p)ni(nip)(mip)μ(i)
再令T=ip,那么就有ans=nT(nT)(mT)p|Tisprime(p)μ(Tp)
然后预处理后面那一块的前缀和就好了,具体情况看代码

#include <map>#include <set>#include <cmath>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 1e7+10;ll prime[maxn],mob[maxn],vis[maxn],sum[maxn],cnt;void Mobius(){    memset(prime,0,sizeof(prime));    memset(mob,0,sizeof(mob));    memset(vis,0,sizeof(vis));    mob[1] = 1;    cnt = 0;    for(ll i = 2;i < maxn; i++){        if(!vis[i]){            prime[cnt++] = i;            mob[i] = -1;        }        for(ll j = 0;j < cnt&&i*prime[j] < maxn;j++){            vis[i*prime[j]] = 1;            if(i%prime[j]) mob[i*prime[j]] = -mob[i];            else{                mob[i*prime[j]] = 0;                break;            }        }    }    for(ll i = 0;i < cnt;i++)        for(ll j = 1;prime[i]*j <= maxn;j++)            sum[prime[i]*j] += mob[j];    for(ll i = 1;i <= maxn;i++)        sum[i] = sum[i-1]+sum[i];}ll cal(ll n,ll m){    if(n > m) swap(n,m);    ll ans = 0,j;    for(ll i = 1;i <= n;i = j+1){        j = min(n/(n/i),m/(m/i));        ans += (sum[j]-sum[i-1])*(n/i)*(m/i);    }    return ans;}int main(){    Mobius();    ll T,n,m;    scanf("%lld",&T);    while(T--){        scanf("%lld%lld",&n,&m);        printf("%lld\n",cal(n,m));    }    return 0;}
原创粉丝点击