基础数论函数练习题

Problem

(n) 个数,每个数为 (a_i),有 (Q) 次询问,每次询问 ([l,r]),求 (LCM_{i=l}^r a_i)。总共 (T) 组数据。

数据范围:(1leq n, Q, Tleq 300)(1leq a_ileq 2^{60})

Solution

首先暴力分解质因数然后搞的最多只有 (40) 分。

考虑另一种暴力:将 (LCM) 表示成若干个数的乘积以避免数字太大。记 (lcm_{l,r}=LCM_{i=l}^r),我们用 (r-l+1) 个数 (b_i) 的乘积表示 (lcm_{l,r})。考虑纳入 (a_{r+1}),注意到 (lcm_{l,r+1}=dfrac{lcm_{l,r} imes a_{r+1}}{(lcm_{l,r},a_{r+1})}),增加的因子为 (dfrac{a_{r+1}}{(lcm_{l,r},a_{r+1})}),将其记为 (b_{r+1}),利用 ((a,b)=(amod b,b)) 求解。通过这样我们可以用 (mathcal O(Tn^3log V)) 的复杂度求解,其中 (V)(a_i) 的最大值。

使用分治优化:考虑求解(lcm_{i,j}),其中 (lleq ileq mid,mid<jleq r)。首先求出来 (lcm_{l,mid}=prod_{i=l}^{mid}b_i^{[L]})(lcm_{mid+1, r}=prod_{i=mid+1}^rb_{i}^{[R]})。注意这里求解 (b^{[L]}) 从右往左,(b^{[R]}) 从左往右,这样满足 (lcm_{i,mid}=prod_{j=i}^{mid}b_j^{[L]})(lcm_{mid+1,i}=prod_{j=mid+1}^ib_j^{[R]})

接下来将 (lcm_{i,mid}) 逐个因子地合并到右边。从 (mid)(l),每次枚举一个因子 (b_i^{[L]}),让其从左往右继续使用 ((A,prod_i B_i)), 对 (b_j^{[R]}) 消公约数。此时可以求出 (Ans_{i,j}=prod _iA_iprod_i B_i)。复杂度 (mathcal O(Tn^2log V))

使用技巧将复杂度降成 (mathcal O(Tn(n+log nlog V)))。发现复杂度瓶颈在求 (Ans_{i,j}) 这里,是由于求 GCD 的缘故。采用下列方法将复杂度由 一次 (mathcal O(nlog V)) 降成 (mathcal O(log V))。注意到这里我们实际上要做的是这样的过程

t = b[i];
for j = mid+1 -> r
	d = (t, b[j]);
	t = t / d;
	b[j] = b[j] / d;

这里 (t) 约分不超过 (log b_i) 次,说明只有 (leqlog b_i)(d e 1)。令 (c_j=prod_{mid<kleq j}b_k),则 (prod_{mid<kleq j}d_k=(b_i, c_k))(d_k) 是每次约分的值。记 (G=(b_i,c_r)),当第一次遇到 (b_j mod G e 0) 时,必有 ((b_i,b_j) e (b_i,b_{j+1})),利用 (G'=(G, c_j)) 得到约分的 (d_j=dfrac G{G'})。如此利用下去总 GCD 复杂度仍然为 (mathcal O(log G)leqmathcal O(log V))。加上分治的 (log n),可以通过本题。

Code

#include <bits/stdc++.h>
typedef long long LL;
const int N = 305, P = 1e9 + 7;
int T, n, Q, ans[N][N];
LL a[N], b[N], c[N];
LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
LL mul(LL a, LL b, LL mod) {
	LL t = a * b - (LL)((long double)a / mod * b + 0.5) * mod; t %= mod;
	return t < 0 ? t + mod : t;
}
void solve(int l, int r) {
	if (l == r) { ans[l][r] = a[l] % P; return; }
	int mid = l + r >> 1;
	solve(l, mid), solve(mid + 1, r);
	for (int i = mid; i >= l; i--) {
		LL t = 1;
		for (int j = mid; j > i; j--) t = mul(t, b[j], a[i]);
		b[i] = a[i] / gcd(a[i], t);
	}
	for (int i = mid + 1; i <= r; i++) {
		LL t = 1;
		for (int j = mid + 1; j < i; j++) t = mul(t, b[j], a[i]);
		b[i] = a[i] / gcd(a[i], t);
	}
	int s = 1;
	for (int i = mid; i >= l; i--) {
		c[mid] = 1;
		for (int j = mid + 1; j <= r; j++) c[j] = mul(c[j - 1], b[j], b[i]);
		LL G = gcd(c[r], b[i]);
		for (int j = r; j > mid; j--)
			if (c[j - 1] % G) {
				LL d = gcd(G, c[j - 1]);
				b[j] /= G/d, G = d;
			}
		s = b[i] % P * s % P;
		int s2 = s;
		for (int j = mid + 1; j <= r; j++)
			ans[i][j] = s2 = b[j] % P * s2 % P;
	}
}
int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &Q);
		for (int i = 1; i <= n; i++)
			scanf("%lld", &a[i]);
		solve(1, n);
		for (int i = 1; i <= Q; i++) {
			int l, r; scanf("%d%d", &l, &r);
			printf("%d
", ans[l][r]);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/ac-evil/p/14432614.html