1. 程式人生 > 實用技巧 >luogu P4318 完全平方數

luogu P4318 完全平方數

luogu P4318 完全平方數

今天膜你賽的時候我想推一個 \(\sum\limits_{i=1}^n \mu^2(i)\),結果太弱智了沒推出來,然後就來看了這道題。

首先考慮二分答案。現在問題就轉化為如何求上述式子。

對每個質因子的平方進行容斥,發現對於每個數容斥係數恰好是 \(u(i)\)。所以原式即為 \(\sum\limits_{i=1}^{\lfloor\sqrt n \rfloor}\mu(i)\lfloor \frac{n}{i^2}\rfloor\)。時間複雜度 \(O(\sqrt n+TlogK)\)

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define int long long

using namespace std;

const int N = 100000;
int k, a[N + 9], p[N], cnt, u[N + 9];

void prework()
{
	u[1] = 1;
	for (int i = 2; i <= N; i++)
	{
		if (!a[i])
			a[i] = i, p[++cnt] = i, u[i] = -1;
		for (int j = 1; j <= cnt; j++)
		{
			if (p[j] > a[i] || p[j] > N / i)
				break;
			a[p[j] * i] = p[j];
			if (i % p[j])
				u[p[j] * i] = u[p[j]] * u[i];
		}
	}
}

void init()
{
	scanf("%lld", &k);
}

int check(int n)
{
	int res = 0;
	for (int i = 1; i * i <= n; i++)
		res += u[i] * (n / (i * i));
	return res;
}

void work()
{
	int l = 1, r = 2e10, mid;
	while (l <= r)
	{
		mid = l + r >> 1;
		if (check(mid) < k)
			l = mid + 1;
		else
			r = mid - 1;
	}
	printf("%lld\n", l);
}

signed main()
{
	prework();
	int T;
	scanf("%lld", &T);
	while (T--)
	init(),
	work();
	return 0;
}