Codeforces 1350 C. Orac and LCM

Codeforces 1350 C. Orac and LCM_第1张图片

题意;

求所有对的最小公倍数组成新集合的最大公约数是多少?

假设 a i a_i ai 没有 2 2 2 这个因子,且 a j a_j aj 也没 2 2 2 这个因子,那么 l c m ( a i , a j ) lcm(a_i , a_j) lcm(ai,aj) 就不包含 2 2 2 这个因子

那么 a n s = g c d { l c m ( a i , a j ) ) ∣ i < j } ans = gcd \{lcm(a_i , a_j)) | i < j\} ans=gcd{lcm(ai,aj))i<j} 也就不包含 2 2 2 这个因子

也就是说数组中如果有两个以上的数都不包含某个因子,那么答案也就不包含这个因子

对每个数进行质因子分解,分解后质因子的幂次存于对应质因子的容器中

然后计算答案时判断每个质因子的容器大小是否大于等于 n − 1 n - 1 n1

如果是则说明数组中少于两个数没有这个质因子,则答案必定要乘上这个质因子

至于是该乘上这个质因子的几次方,我们对容器升序排个序

如果容器的大小等于 n n n 则取第二个元素即次小幂次,如果等于 n − 1 n - 1 n1 则取第一个元素即最小幂次

以某质数容器的大小为 n n n 举例 :

最后一个元素对应最大幂次,只有一个数包含了这个它,倒数第二个元素对应次大幂次,有两个数包含了它

以此类推第二个元素对应次小幂次,有 n − 1 n - 1 n1 个数包含了它,第一个元素为最小次幂,有 n n n 个数包含了它

因为只需要 n − 1 n - 1 n1个数有包含它答案就可以乘上它,所以我们选第二个元素作为幂次。

AC代码:

const int N = 2e5 + 50;
int n, k;
int ans, res, tmp;
int vis[N], a[N], prime[N], cnt;
vector<int> v[N];

void init()
{
	vis[1] = 1;
	rep(i, 2, N - 10)
	{
		if (!vis[i])
			prime[++cnt] = i;
		for (int j = 1; j <= cnt && i * prime[j] <= N - 10; j++)
		{
			vis[i * prime[j]] = 1;
			if (i % prime[j] == 0)
				break;
		}
	}
}

void cal(int x)
{
	rep(i, 1, cnt)
	{
		if (prime[i] * prime[i] > x)
			break;
		if (x % prime[i] == 0)
		{
			int num = 0;
			while (x % prime[i] == 0)
			{
				x /= prime[i];
				num++;
			}
			v[prime[i]].pb(num); //质因子分解
		}
	}
	if (x > 1)
		v[x].pb(1);//x为质数
}

int main()
{
	init();
	ans = 1;
	sd(n);
	rep(i, 1, n)
	{
		sd(a[i]);
		cal(a[i]);
	}
	rep(i, 1, cnt)
	{
		int x = prime[i];
		sort(v[x].begin(), v[x].end());
		if ((v[x].size()) == n)
		{
			int y = max(v[x][0], v[x][1]);
			tmp = 1;
			rep(i, 1, y)
				tmp *= x;
			ans *= tmp;
		}
		if ((v[x].size()) == n - 1)
		{
			int y = v[x][0];
			tmp = 1;
			rep(i, 1, y)
				tmp *= x;
			ans *= tmp;
		}
	}
	pd(ans);
	return 0;
}

你可能感兴趣的:(CodeForces)