1. 程式人生 > >FJUT3565 最大公約數之和(容斥)題解

FJUT3565 最大公約數之和(容斥)題解

題意:給n,m,求出圖片.png

思路:題意為求出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; }