【题解】Luogu-P5221 Product

P5221 Product

Description

  • 给定整数 n n n,请求出
    [ ∏ i = 1 n ∏ j = 1 n lcm ⁡ ( i , j ) gcd ⁡ ( i , j ) ]   m o d   104857601 \left[\prod_{i = 1}^n \prod_{j = 1}^n \dfrac{\operatorname{lcm}(i, j)}{\gcd(i, j)} \right] \bmod 104857601 [i=1nj=1ngcd(i,j)lcm(i,j)]mod104857601

  • 对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 6 1\le n\le 10^6 1n106

Solution

∏ i = 1 n ∏ j = 1 n lcm ⁡ ( i , j ) gcd ⁡ ( i , j ) = ∏ i = 1 n ∏ j = 1 n i j gcd ⁡ ( i , j ) 2 = ∏ i = 1 n ∏ j = 1 n i j [ ∏ i = 1 n ∏ j = 1 n gcd ⁡ ( i , j ) ] 2 \begin{aligned} \prod_{i = 1}^n \prod_{j = 1}^n \dfrac{\operatorname{lcm}(i, j)}{\gcd(i, j)} & = \prod_{i = 1}^n \prod_{j = 1}^n \dfrac{ij}{\gcd(i, j)^2} \\ & = \dfrac{\prod\limits_{i = 1}^n \prod\limits_{j = 1}^n ij}{\left[\prod\limits_{i = 1}^n \prod\limits_{j = 1}^n \gcd(i, j) \right]^2} \end{aligned} i=1nj=1ngcd(i,j)lcm(i,j)=i=1nj=1ngcd(i,j)2ij=[i=1nj=1ngcd(i,j)]2i=1nj=1nij
对于分子
∏ i = 1 n ∏ j = 1 n i j = ∏ i = 1 n i n ⋅ n ! = ( n ! ) n ⋅ ( n ! ) n = ( n ! ) 2 n \begin{aligned} \prod_{i = 1}^n \prod_{j = 1}^n ij & = \prod_{i = 1}^n i^n\cdot n! \\ & = (n!)^n \cdot (n!)^n \\ & = (n!)^{2n} \end{aligned} i=1nj=1nij=i=1ninn!=(n!)n(n!)n=(n!)2n
对于分母(忽略 2 2 2 次方)
∏ i = 1 n ∏ j = 1 n gcd ⁡ ( i , j ) = ∏ d = 1 n ∏ i = 1 n ∏ j = 1 n d [ gcd ⁡ ( i , j ) = d ] = ∏ d = 1 n ∏ i = 1 ⌊ n d ⌋ ∏ j = 1 ⌊ n d ⌋ d [ gcd ⁡ ( i , j ) = 1 ] = ∏ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ gcd ⁡ ( i , j ) = 1 ] \begin{aligned} \prod_{i = 1}^n \prod_{j = 1}^n \gcd(i, j) & = \prod_{d = 1}^n \prod_{i = 1}^n \prod_{j = 1}^n d[\gcd(i, j) = d] \\ & = \prod_{d = 1}^n \prod_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \prod_{j = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} d[\gcd(i, j) = 1] \\ & = \prod_{d = 1}^n d^{\sum_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \sum_{j = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} [\gcd(i, j) = 1]} \end{aligned} i=1nj=1ngcd(i,j)=d=1ni=1nj=1nd[gcd(i,j)=d]=d=1ni=1dnj=1dnd[gcd(i,j)=1]=d=1ndi=1dnj=1dn[gcd(i,j)=1]
拆指数
∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ gcd ⁡ ( i , j ) = 1 ] = ∑ k = 1 ⌊ n d ⌋ μ ( k ) ⌊ n d k ⌋ 2 \sum_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \sum_{j = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} [\gcd(i, j) = 1] = \sum_{k = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \mu(k) \left\lfloor\dfrac{n}{dk}\right\rfloor^2 i=1dnj=1dn[gcd(i,j)=1]=k=1dnμ(k)dkn2

代回去
∏ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ gcd ⁡ ( i , j ) = 1 ] = ∏ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) ⌊ n d k ⌋ 2 \prod_{d = 1}^n d^{\sum_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \sum_{j = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} [\gcd(i, j) = 1]} = \prod_{d = 1}^n d^{\sum_{k = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \mu(k) \left\lfloor\frac{n}{dk}\right\rfloor^2} d=1ndi=1dnj=1dn[gcd(i,j)=1]=d=1ndk=1dnμ(k)dkn2
指数用欧拉定理   m o d   ( p − 1 ) \bmod (p - 1) mod(p1) 转成正数并降至 O ( p ) \Omicron(p) O(p) 级别。

暴力枚举 + 整除分块。

时间复杂度为 O ( ∑ i = 1 n n i ⋅ log ⁡ p ) = O ( log ⁡ p ∑ i = 1 n n i ) \Omicron\left(\sum_{i = 1}^n \sqrt{\dfrac{n}{i}} \cdot \log p \right) = \Omicron(\log p \sum_{i = 1}^n \sqrt{\dfrac{n}{i}}) O(i=1nin logp)=O(logpi=1nin )

当积分算
∫ 1 n n x   d x = 2 n − 2 n \int_1^n \sqrt{\dfrac{n}{x}}\, dx = 2n - 2\sqrt{n} 1nxn dx=2n2n

所以整个是 O ( n log ⁡ p ) \Omicron(n\log p) O(nlogp) 的。

注意本题卡空间, μ \mu μ 数组的前缀和直接覆盖到 μ \mu μ 数组上即可。

Code

// 18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#define Debug(x) cout << #x << "=" << x << endl
typedef long long ll;
using namespace std;

const int MAXN = 1e6 + 5;
const int MOD = 104857601;

int p[MAXN / 10], mu[MAXN];
bool vis[MAXN];

void pre(int n)
{
	mu[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		if (!vis[i])
		{
			p[++p[0]] = i;
			mu[i] = -1;
		}
		for (int j = 1; j <= p[0] && i * p[j] <= n; j++)
		{
			vis[i * p[j]] = true;
			if (i % p[j] == 0)
			{
				mu[i * p[j]] = 0;
				break;
			}
			mu[i * p[j]] = mu[i] * mu[p[j]];
		}
	}
	for (int i = 1; i <= n; i++)
	{
		mu[i] = (mu[i - 1] + mu[i] + MOD - 1) % (MOD - 1);
	}
}

int GetSum(int l, int r)
{
	return (mu[r] - mu[l - 1] + MOD - 1) % (MOD - 1);
}

int block(int n)
{
	int res = 0;
	for (int l = 1, r; l <= n; l = r + 1)
	{
		int k = n / l;
		r = n / k;
		res = (res + (ll)GetSum(l, r) * k % (MOD - 1) * k % (MOD - 1)) % (MOD - 1);
	}
	return res;
}

int qpow(int a, int b)
{
	int base = a, ans = 1;
	while (b)
	{
		if (b & 1)
		{
			ans = (ll)ans * base % MOD;
		}
		base = (ll)base * base % MOD;
		b >>= 1;
	}
	return ans;
}

int inv(int a)
{
	return qpow(a, MOD - 2);
}

int main()
{
	int n;
	scanf("%d", &n);
	pre(n);
	int fac = 1;
	for (int i = 1; i <= n; i++)
	{
		fac = (ll)fac * i % MOD;
	}
	fac = qpow(fac, 2 * n);
	int ans = 1;
	for (int i = 1; i <= n; i++)
	{
		ans = (ll)ans * qpow(i, block(n / i)) % MOD;
	}
	printf("%d\n", (ll)fac * inv((ll)ans * ans % MOD) % MOD);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值