【LG-P3704 [SDOI2017]】数字表格

这篇博客探讨了一个涉及斐波那契函数与最大公约数的数学问题,通过数论分块和预处理优化,实现了高效计算给定范围内所有整数对的最大公约数的斐波那契函数值的乘积。文章提供了详细的推导过程和C++代码实现,展示了如何利用斐波那契数列的性质进行计算优化。
摘要由CSDN通过智能技术生成

P3704 [SDOI2017]数字表格

f f f 为斐波那契函数,求

∏ i = 1 n ∏ j = 1 m f gcd ⁡ ( i , j ) \prod_{i=1}^n\prod_{j=1}^mf_{\gcd(i,j)} i=1nj=1mfgcd(i,j)


推柿子:

n ≤ m n\leq m nm

∏ i = 1 n ∏ j = 1 m f gcd ⁡ ( i , j ) \prod_{i=1}^n\prod_{j=1}^mf_{\gcd(i,j)} i=1nj=1mfgcd(i,j)

= ∏ d = 1 n f ( d ) ∏ i = 1 [ n d ] ∏ j = 1 [ m d ] [ gcd ⁡ ( i , j ) = 1 ] =\prod_{d=1}^n f(d)\prod_{i=1}^{[\frac{n}{d}]}\prod_{j=1}^{[\frac{m}{d}]}[\gcd(i,j)=1] =d=1nf(d)i=1[dn]j=1[dm][gcd(i,j)=1]

= ∏ d = 1 n f ( d ) ∑ i = 1 [ n d ] ∑ j = 1 [ m d ] [ gcd ⁡ ( i , j ) = 1 ] =\prod_{d=1}^n f(d)^{\sum\limits_{i=1}^{[\frac{n}{d}]}\sum\limits_{j=1}^{[\frac{m}{d}]}[\gcd(i,j)=1]} =d=1nf(d)i=1[dn]j=1[dm][gcd(i,j)=1]

= ∏ d = 1 n f ( d ) ∑ i = 1 [ n d ] [ n i d ] [ m i d ] μ ( i ) =\prod_{d=1}^n f(d)^{\sum\limits_{i=1}^{[\frac{n}{d}]}[\frac{n}{id}][\frac{m}{id}]\mu(i)} =d=1nf(d)i=1[dn][idn][idm]μ(i)

= ∏ T = 1 n ∏ d ∣ T f ( d ) [ n T ] [ m T ] μ ( T d ) =\prod_{T=1}^n\prod_{d|T}f(d)^{[\frac{n}{T}][\frac{m}{T}]\mu(\frac{T}{d})} =T=1ndTf(d)[Tn][Tm]μ(dT)

= ∏ T = 1 n [ n T ] [ m T ] ∏ d ∣ T f ( d ) μ ( T d ) \boxed{=\prod_{T=1}^n[\frac{n}{T}][\frac{m}{T}]\prod_{d|T}f(d)\mu(\frac{T}{d})} =T=1n[Tn][Tm]dTf(d)μ(dT)


前半部分数论分块,后半部分预处理。

预处理一个数组 F F F F k = ∏ i = 1 k ∏ x ∣ i f ( x ) μ ( i x ) F_k=\prod_{i=1}^k\prod_{x|i}f(x)\mu(\frac{i}{x}) Fk=i=1kxif(x)μ(xi)

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

#define rep(i, a, b) for(int i = a; i <= b; ++i)

const int mod = 1e9 + 7;
const int maxn = 1e6 + 5;
const int N = 1e6;
int T, n, m;
bool vis[maxn];
int tot, f[maxn], F[maxn], inv[maxn], prm[maxn], mu[maxn];

inline int power(int x, int p)
{
	int res = 1;
	while(p > 0)
	{
		if(p & 1)
			res = 1ll * res * x % mod;
		p /= 2, x = 1ll * x * x % mod;
	}
	return res;
}

inline void pre()
{
	F[0] = F[1] = mu[1] = f[1] = inv[1] = vis[1] = 1;
	rep(i, 2, N)
	{
		f[i] = (f[i - 1] + f[i - 2]) % mod;
		F[i] = 1, inv[i] = power(f[i], mod - 2);
		if(!vis[i]) mu[i] = -1, prm[++tot] = i;
		rep(j, 1, tot)
		{
			if(i * prm[j] > N) break;
			vis[i * prm[j]] = 1;
			if(i % prm[j] == 0) break;
			mu[i * prm[j]] = -mu[i];
		}
	}
	rep(i, 1, N) if(mu[i])
		for(int j = i; j <= N; j += i)  
			F[j] = 1ll * F[j] * (mu[i] == 1 ? f[j / i] : inv[j / i]) % mod;
	rep(i, 2, N) F[i] = 1ll * F[i] * F[i - 1] % mod;
}

int main()
{
	pre();
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d %d", &n, &m);
		if(n > m) swap(n, m);
		int ans = 1;
		for(int l = 1, r; l <= n; l = r + 1)
		{
			r = min(n / (n / l), m / (m / l));
			int k = 1ll * F[r] * power(F[l - 1], mod - 2) % mod;
			ans = 1ll * ans * power(k, 1ll * (n / l) * (m / l) % (mod - 1)) % mod;
		}
		printf("%d\n", (ans + mod) % mod);
	}
	return 0;
}

—— E n d End End——

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值