码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-11-01 13:35:00      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:define   turn   math   scan   idt   prim   代码   lld   最大   

题意:给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\n", ans);
    return 0;
}

 

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

标签:define   turn   math   scan   idt   prim   代码   lld   最大   

原文地址:https://www.cnblogs.com/KirinSB/p/9888543.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!