最容易理解的莫比乌斯反演

对于给出的n个询问,每次求有多少个数对(x,y),满足axbcyd,且gcd(x,y) = kgcd(x,y)函数为xy的最大公约数

1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

Sample Input
2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3




最容易理解的莫比乌斯反演_第1张图片最容易理解的莫比乌斯反演_第2张图片


最容易理解的莫比乌斯反演_第3张图片


最容易理解的莫比乌斯反演_第4张图片

上叙对于区间最远的端点的理解:

若a为10,x为 4 ,因为 10除以4有余数,所以会存在x在扩大的过程中尽量减少这个余数,很容易知道当x为5的时候刚好没有余数,同时他们的商都是2

最后发现,其实上面叙述的P 其实就是莫比乌斯函数

而莫比乌斯函数反演有两种形式,一般是第二种:

最容易理解的莫比乌斯反演_第5张图片

从这两个形式中可以发现莫比乌斯函数的两个应用:

对于一些函数,我们很难直接求他的值,但是很容易求这个函数的倍数或者约数的值

此时我们可以用莫比乌斯反演得到此函数,本题就是这么个道理





#include
#include
#include
using namespace std;

#define MAXN 100000
#define LL long long
bool check[MAXN+10];
int primer[MAXN+10];
int mu[MAXN+10];
int sum[MAXN+10];

void Moblus()
{
    memset(check,0,sizeof(check));
    mu[1]=1;
    int tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]){
            primer[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;jm) swap(n,m);
    for(int i=1,last;i<=n;i=last+1){
        last=min(n/(n/i),m/(m/i));
        ans+=(LL)(sum[last]-sum[i-1])*(n/i)*(m/i);
    }
    return ans;
}

int main()
{
    int T;
    Moblus();
    int a,b,c,d,k;
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);

        LL ans=solve(b/k,d/k)-solve((a-1)/k,d/k)
        -solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
        printf("%lld\n",ans);
    }
    return 0;
}



Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.

Yoiu can assume that a = c = 1 in all test cases.

Input The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
Output For each test case, print the number of choices. Use the format in the example.
Sample Input
2
1 3 1 5 1
1 11014 1 14409 9
Sample Output
Case 1: 9
Case 2: 736427


        
  
Hint
For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).
        
 


本题和上题不同的是,需要去重

(1,2)和(2,1)是一样的



#include
#include
#include
using namespace std;

#define MAXN 1000000
#define LL long long
bool check[MAXN+10];
LL primer[MAXN+10];
LL mu[MAXN+10];
LL sum[MAXN+10];

void Moblus()
{
    memset(check,0,sizeof(check));
    mu[1]=1;
    int tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]){
            primer[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;jm) swap(n,m);
    for(int i=1,last;i<=n;i=last+1){
        last=min(n/(n/i),m/(m/i));
        ans+=(LL)(sum[last]-sum[i-1])*((LL)(n/i)*(m/i));
    }
    return ans;
}

int main()
{
    int T;
    Moblus();
    int a,b,c,d,k,cases=1;
   // freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        printf("Case %d: ",cases++);
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if(k==0){
            puts("0");
            continue;
        }
        LL ans=solve(b/k,d/k)-solve((a-1)/k,d/k)
        -solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
        int x=max(a,c);
        int y=min(b,d);
        if(y>=x){
            ans-=solve(y/k,y/k)/2;
            ans+=solve(x/k,x/k)/2;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}



你可能感兴趣的:(数论——基础问题,acm)