icpc2020江西ICPC省赛 A.Simple Math Problem (莫比乌斯反演)

题目链接:https://ac.nowcoder.com/acm/contest/8827/A

枚举 \(gcd\),则答案应为

\[\sum\limits_{d=1}^n \mu(d) \sum\limits_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum\limits_{j=1}^{\lfloor \frac{i}{d}\rfloor} F(jd) \]

交换 \(i,j\) 的枚举顺序,得到

\[\sum\limits_{d=1}^n \mu(d) \sum\limits_{j=1}^{\lfloor \frac{n}{d}\rfloor} F(jd)(\lfloor \frac{n}{d}\rfloor-j+1 ) \]

枚举倍数 \(O(nlogn)\) 计算即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int n;

int cnt = 0;
int prime[maxn], mu[maxn], is_prime[maxn];

int f[maxn];
int count(int x){
	int tmp = x;
	int res = 0;
	while(tmp){
		res += tmp % 10;
		tmp /= 10;
	}
	return res;
}

ll solve(int d){
	ll res = 0;
	for(int i = 1 ; i * d <= n ; ++i){
		res += 1ll * f[i*d] * (n/d-i+1);
	} 
	return 1ll * res * mu[d];
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	mu[1] = 1;
	for(int i = 2; i <= 100000; ++i){
		if(!is_prime[i]){
			prime[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1 ; j <= cnt && prime[j] * i <= 100000 ; ++j){
			is_prime[i * prime[j]] = 1;
			if(i % prime[j] == 0) {
				mu[i * prime[j]] = 0;
				break;
			} else {
				mu[i * prime[j]] = -mu[i];
			}
		}
	}
	
	n = read();
	for(int i = 1 ; i <= n ; ++i){ f[i] = count(i); }
	
	ll ans = 0;
	for(int d = 1 ; d <= n ; ++d){
		ans += solve(d);
	}
	
	printf("%lld\n", ans);
	
	return 0;
}
posted @ 2021-09-09 22:27  Tartarus_li  阅读(76)  评论(0编辑  收藏  举报