1. 程式人生 > >新視野OJ 2301 [HAOI2011]Problem b (數論-gcd)

新視野OJ 2301 [HAOI2011]Problem b (數論-gcd)

題意:對於給出的n個詢問,每次求有多少個數對(x,y),滿足a≤x≤b,c≤y≤d,且gcd(x,y) = k。

題解:和前幾道題差不多,就是xy不是從1開始了,所以我們很容易聯想到容斥原理,ans=gcd(b,d)-gcd(a-1,d)-gcd(b,c-1)+gcd(a-1,b-1)。

AC程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <iterator>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <cctype>
using namespace std;

#define si1(a) scanf("%d",&a)
#define si2(a,b) scanf("%d%d",&a,&b)
#define sd1(a) scanf("%lf",&a)
#define sd2(a,b) scanf("%lf%lf",&a,&b)
#define ss1(s)  scanf("%s",s)
#define pi1(a)    printf("%d\n",a)
#define pi2(a,b)  printf("%d %d\n",a,b)
#define mset(a,b)   memset(a,b,sizeof(a))
#define forb(i,a,b)   for(int i=a;i<b;i++)
#define ford(i,a,b)   for(int i=a;i<=b;i++)

typedef long long LL;
const int N=500005;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-7;

LL f[N];
LL k;

LL xiaohao(LL n,LL m)
{
    if(n<k||m<k)    return 0;
    if(n>m) swap(n,m);
    n/=k;   m/=k;

    LL sum=0;
    for(LL i=n;i>=1;i--)
    {
        f[i]=(n/i)*(m/i);
        for(LL j=i+i;j<=n;j+=i)
            f[i]-=f[j];
    }
    return f[1];
}

int main()
{
//    freopen("input.txt","r",stdin);
    LL a,b,c,d;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        //scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
        cin>>a>>b>>c>>d>>k;

        if(a>b||c>d)
        {
            puts("0");
            continue;
        }
        cout<<xiaohao(b,d)-xiaohao(a-1,d)-xiaohao(c,b-1)+xiaohao(a-1,b-1)<<endl;
    }
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <iterator>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <cctype>
using namespace std;

#define si1(a) scanf("%d",&a)
#define si2(a,b) scanf("%d%d",&a,&b)
#define sd1(a) scanf("%lf",&a)
#define sd2(a,b) scanf("%lf%lf",&a,&b)
#define ss1(s)  scanf("%s",s)
#define pi1(a)    printf("%d\n",a)
#define pi2(a,b)  printf("%d %d\n",a,b)
#define mset(a,b)   memset(a,b,sizeof(a))
#define forb(i,a,b)   for(int i=a;i<b;i++)
#define ford(i,a,b)   for(int i=a;i<=b;i++)

typedef long long LL;
const int N=50000;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-7;

LL x;
LL A,B,C,D,K;
LL mu[N+10],sum[N+10],prime[N+10];
bool com[N+1];

void GetPrimes()
{
    memset(com,0,sizeof(com));
    mu[1]=1;
    x=0;
    for(LL i=2;i<=N;++i)
    {
        if (!com[i])    { prime[x++] = i; mu[i] = -1; }
        for (LL j=0;j<x&&i*prime[j]<=N;++j)
        {
            com[i*prime[j]] = true;
            if (i%prime[j]) mu[i*prime[j]] = -mu[i];
            else { mu[i*prime[j]] = 0; break; }
        }
    }
    for (LL i=1;i<=N;++i)
        sum[i] = sum[i-1] + mu[i];
}

LL Process(LL n,LL m)
{
    LL res=0;
    if(n>m) swap(n,m);
    for(LL i=1,last=0;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        res+=(sum[last]-sum[i-1])*(n/i)*(m/i);
    }
    return res;
}

int main()
{
//    freopen("input.txt","r",stdin);
    GetPrimes();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld%lld%lld",&A,&B,&C,&D,&K);
        LL ans=0;
        ans+=Process(B/K,D/K);
        ans-=Process((A-1)/K,D/K);
        ans-=Process(B/K,(C-1)/K);
        ans+=Process((A-1)/K,(C-1)/K);
        printf("%lld\n",ans);
    }
}