SP4168 SQFREE - Square-free integers

题目描述

在数论中,如果一个整数不能被任何一个整数(这个整数不是\(1\))的平方整除,我们就称它是一个\(Square-free integer\)(无平方数因数的数)。你得数一数!

题解

利用容斥的思想,\(1\)\(n\)以内有平方因数的数有\(\frac{n}{2^2} + \frac{n}{3^2} + \frac{n}{5^2} - \frac{n}{6^2} ...\)

可知以上式子为\(- \displaystyle \sum _{2 \leq d \leq \sqrt n} \mu (d) * (n / d^2)\),所以无平方因数的数有\(n + \displaystyle \sum _{2 \leq d \leq \sqrt n} \mu (d) * (n / d^2)\)个。

合并一下,我们发现这个式子其实就是\(\displaystyle \sum _{1 \leq d \leq \sqrt n} \mu (d) * (n / d^2)\)

然后数论分块就好了(# ^ . ^ #)。

#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const int N = 1e7;
int T, tot, vis[N + 5], prime[N + 5], mu[N + 5], s1[N + 5], s2[N + 5];
ll n;
inline ll read()
{
	ll x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void init(int n)
{
	mu[1] = 1;
	for(int i = 2; i <= n; i ++)
	{
		if(!vis[i]) {prime[++ tot] = i; mu[i] = -1;}
		for(int j = 1; j <= tot && i * prime[j] <= n; j ++)
		{
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0) break;
			mu[i * prime[j]] = - mu[i];
		}
	}
	for(int i = 1; i <= n; i ++) s1[i] = s1[i - 1] + mu[i], s2[i] = s2[i - 1] + mu[i] * mu[i];
}
ll calc(ll n)
{
	if(n <= N) return s2[n];
	ll res = 0, m = sqrt(n);
	for(ll l = 1, r; l <= m; l = r + 1)
	{
		r = min((ll)sqrt(n / (n / (l * l))), m);
		res += (n / (l * l)) * (s1[r] - s1[l - 1]);
	}
	return res;
}
void work()
{
	T = read(); init(1e7);
	while(T -- > 0)
	{
		n = read();
		printf("%lld\n", calc(n));
	}
}
int main() {return work(), 0;}
posted @ 2020-04-01 10:59  Sunny_r  阅读(187)  评论(1编辑  收藏  举报