LOJ530 「LibreOJ β Round #5」最小倍數(二分)

文章目錄

題目

「LibreOJ β Round #5」最小倍數

分析

n!=p1a1p2a2pkakn! = {p_1}^{a_1}{p_2}^{a_2} \cdots {p_k}^{a_k},那麼ai=j=1npija_i = \sum\limits_{j = 1}^{\infty} \left\lfloor \dfrac{n}{{p_i}^j} \right\rfloor,其實就是統計11nnpip_i的倍數有多少個,pi2{p_i}^2的倍數有多少個……加起來(沒有乘jj的原因是後面的數也會被前面統計到)即可。

於是愉快地二分判一下各個因子個數是不是不小於給定的值即可。

代碼

#include <algorithm>
#include <cstdio>
#include <cstring>

typedef long long LL;

LL Read() {
	LL x = 0; char c = getchar();
	while (c < '0' || c > '9')
		c = getchar();
	while (c >= '0' && c <= '9')
		x = x * 10 + (c ^ 48), c = getchar();
	return x;
}

const int MAXM = 100;
const int MAXP = 600;
const LL INF = 1e18;

bool Vis[MAXP + 5];
int P[MAXM + 5], cnt;

int M;
LL E[MAXM + 5];

int main() {
//	freopen("div.in", "r", stdin);
//	freopen("div.out", "w", stdout);
	for (int i = 2; i <= MAXP; i++) {
		if (!Vis[i])
			P[++cnt] = i;
		for (int j = 1; j <= cnt && i * P[j] <= MAXP; j++) {
			Vis[i * P[j]] = true;
			if (i % P[j] == 0)
				break;
		}
	}
	int T = Read();
	while (T--) {
		M = Read();
		LL lft = 0, rgt = 1;
		for (int i = 1; i <= M; i++) {
			E[i] = Read();
			rgt = std::max(rgt, E[i] * P[i]);
		}
		while (lft + 1 < rgt) {
			LL mid = (rgt + lft) >> 1;
			bool flag = true;
			for (int i = 1; i <= M; i++) {
				LL tmp = mid, res = 0;
				while (tmp && res < E[i]) {
					res += tmp / P[i];
					tmp /= P[i];
				}
				if (res < E[i]) {
					flag = false;
					break;
				}
			}
			if (flag)
				rgt = mid;
			else
				lft = mid;
		}
		printf("%lld\n", rgt);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章