【题解&总结】 P3704 [SDOI2017]数字表格

本文解析了一道涉及斐波那契数列与最大公约数的数学问题,通过莫比乌斯反演技巧,给出了一个时间复杂度优化的解法,展示了如何用O(n log^2 n + T sqrt n)计算乘积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题真是本人切的第一道黑题,我还是太弱了

题目大意

给定 n,mn,mn,m ,求 ∏i=1n∏j=1mfgcd(i,j)\prod_{i=1}^n\prod_{j=1}^mf_{gcd(i,j)}i=1nj=1mfgcd(i,j) 其中,fff 为斐波那契数列。

题解

考虑枚举 d=gcd(i,j)d=gcd(i,j)d=gcd(i,j) ,思考会存在多少个 fdf_dfd ,即 ∑i∑j[gcd(i,j)==d]\sum_i\sum_j[gcd(i,j)==d]ij[gcd(i,j)==d] ,则原式可化为
∏d=1nfd∑i=1n∑j=1m[gcd(i,j)==d]\prod_{d=1}^nf_d^{\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]}d=1nfdi=1nj=1m[gcd(i,j)==d]
观察 ∑i=1n∑j=1m[gcd(i,j)==d]\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]i=1nj=1m[gcd(i,j)==d] ,经典莫比乌斯反演,考虑化简,得
∑i=1⌊nd⌋∑j=1⌊md⌋∑k∣gcd(i,j)μ(k)=∑k=1min(⌊nd⌋,⌊md⌋)μ(k)⋅⌊nkd⌋⋅⌊mkd⌋\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{k|gcd(i,j)}\mu(k)\\ =\sum_{k=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\mu(k)\cdot \lfloor\frac{n}{kd}\rfloor \cdot\lfloor\frac{m}{kd}\rfloor i=1dnj=1dmkgcd(i,j)μ(k)=k=1min(dn,dm)μ(k)kdnkdm
接下来设 T=kdT=kdT=kd ,并枚举 TTT ,代入原式得
∏T=1min(n,m)(∏d∣Tfdμ(Td))⌊nT⌋⌊mT⌋\prod_{T=1}^{min(n,m)}(\prod_{d|T}f_{d}^{\mu(\frac{T}{d})})^{\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor}T=1min(n,m)(dTfdμ(dT))TnTm
F(T)=∏d∣Tfdμ(Td)F(T)=\prod_{d|T}f_{d}^{\mu(\frac{T}{d})}F(T)=dTfdμ(dT) , 可以用 O(nlog2n)O(nlog_2n)O(nlog2n) 的时间复杂度将其预处理,然后将指数分块,时间复杂度 O(nlog2n+Tn)O(nlog_2n+T\sqrt n)O(nlog2n+Tn)

Code

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int N=1e6+5;
const ll P=1e9+7;
int n,m,cnt;
int prime[N];
ll mu[N],f[N],g[N],F[N],s[N],Inv[N];
bool bz[N];
ll ksm(ll a,ll b){
	ll res=1;
	for (;b;b>>=1,a=a*a%P)
		if (b&1) res=res*a%P;
	return res;
}
void work(){
	mu[1]=1;f[0]=0;f[1]=1;g[1]=1;F[1]=1;
	for (int i=2;i<=N-5;++i){
		if (!bz[i]){
			bz[i]=1;
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for (int j=1;j<=cnt&&i*prime[j]<=N-5;++j){
			bz[i*prime[j]]=1;
			if (i%prime[j]) mu[i*prime[j]]=-mu[i];
			else break;
		}
		f[i]=(f[i-1]+f[i-2])%P;
		g[i]=ksm(f[i],P-2);
		F[i]=1;
	}
	for (int i=1;i<=N-5;++i){
		if (mu[i]==0) continue;
		for (int j=i;j<=N-5;j+=i)
			F[j]=F[j]*(mu[i]==1?f[j/i]:g[j/i])%P;
	}
	s[0]=1;Inv[0]=1;
	for (int i=1;i<=N-5;++i) s[i]=s[i-1]*F[i]%P;
	for (int i=1;i<=N-5;++i) Inv[i]=ksm(s[i],P-2);
	return;
}
int main(){
	work();
	int Q;
	scanf("%d",&Q);
	ll ans;
	while (Q--){
		scanf("%d%d",&n,&m);
		ans=1;
		for (int l=1,r=0;l<=min(n,m);l=r+1){
			r=min(n/(n/l),m/(m/l));
			ans=ans*ksm(s[r]*Inv[l-1]%P,(ll)(n/l)*(ll)(m/l))%P;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值