FJUT3565 最大公约数之和(容斥)题解

Posted kirinsb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FJUT3565 最大公约数之和(容斥)题解相关的知识,希望对你有一定的参考价值。

题意:给n,m,求出技术分享图片

思路:题意为求出1~m所有数和n的gcd之和。显然gcd为n的因数。我们都知道gcd(a,b)= c,那么gcd(a/c,b/c)= 1。也就是说我们枚举n所有的因数k,然后去找1~m/k中和n/k互质的个数就是gcd为k的个数。这个直接容斥就行。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x)  x&-x;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1e5+5;
const ll mod = 1e8+7;
ll prime[maxn], p[maxn], pn;
void init(){
    pn = 0;
    memset(prime, 0, sizeof(prime));
    for(ll i = 2; i < maxn; i++){
        if(!prime[i]){
            p[pn++] = i;
            for(ll j = i * i; j < maxn; j += i)
                prime[j] = 1;
        }
    }
}
ll y[maxn], tot;
ll solve(ll r, ll n){   //返回1~r和n的gcd为1个数
    tot = 0;
    ll N = n;
    for(int i = 0; p[i] * p[i] <= N && i < pn; i++){
        if(N % p[i] == 0){
            y[tot++] = p[i];
            while(N % p[i] == 0)
                N /= p[i];
        }
    }
    if(N > 1) y[tot++] = N;
    ll num = 0;
    for(ll i = 1; i < (1 << tot); i++){
        ll val = 1, times = 0;
        for(ll j = 0; j < tot; j++){
            if((1 << j) & i){
                times++;
                val *= y[j];
            }
        }
        if(times & 1){
            num += r / val;
        }
        else{
            num -= r / val;
        }
    }
    return r - num;
}

int main(){
    ll n, m, num, ans = 0, cnt = 0, temp;
    init();
    scanf("%lld%lld", &n, &m);
    for(ll i = 2; i <= sqrt(n); i++){
        if(n % i == 0){
            num = solve(m / i, n / i);
            ans += num * i;
            cnt += num;
            if(i * i != n){
                temp = n / i;
                num = solve(m / temp, n / temp);
                ans += num * temp;
                cnt += num;
            }
        }
    }
    num = solve(m / n, 1);
    ans += num * n;
    cnt += num;
    ans += m - cnt;
    printf("%lld
", ans);
    return 0;
}

 

以上是关于FJUT3565 最大公约数之和(容斥)题解的主要内容,如果未能解决你的问题,请参考以下文章

FJUT seventh的tired树上路径(01字典树)题解

POJ3565ANTS KM算法

FJUT2019暑假周赛三部分题解

FJUT2017寒假训练二题解

FJUT 聪明的商人(树上倍增)题解

FJUT16级第一周寒假作业题解I题