[SDOI2017]数字表格 Solution

本文探讨了如何求解一个特殊矩阵中所有元素的乘积,该矩阵的每个元素是其坐标位置的最大公约数。通过引入数论技巧,将问题转化为求解一系列涉及莫比乌斯函数和数论分块的计算,最终给出了一种高效的算法实现。

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

题意:定义矩阵内每个位置(i,j)(i,j)(i,j)的数为gcd⁡(i,j)\gcd(i,j)gcd(i,j),求矩阵内所有数的乘积。
∏k=1nFk∑i=1n∑j=1m[gcd⁡(i,j)=k] \prod^{n}_{k=1}F_k^{\sum^n_{i=1}\sum^{m}_{j=1}[\gcd(i,j)=k]} k=1nFki=1nj=1m[gcd(i,j)=k]
对于左上角的东西直接提出kkk
∑i=1⌊nk⌋∑j=1⌊mk⌋[gcd⁡(i,j)=1]=∑d=1⌊nk⌋μ(d)⌊nk×d⌋⌊mk×d⌋ \sum^{\lfloor\frac{n}{k}\rfloor}_{i=1}\sum^{\lfloor\frac{m}{k}\rfloor}_{j=1}[\gcd(i,j)=1]\\=\sum^{\lfloor\frac{n}{k}\rfloor}_{d=1}\mu(d)\lfloor\frac{n}{k\times d}\rfloor\lfloor\frac{m}{k\times d}\rfloor i=1knj=1km[gcd(i,j)=1]=d=1knμ(d)k×dnk×dm
于是原式就化为
∏R=1n(∏T∣RFTμ(RT))⌊nR⌋×⌊mR⌋ \prod^{n}_{R=1}(\prod_{T|R}F_T^{\mu(\frac{R}{T})})^{\lfloor\frac{n}{R}\rfloor\times \lfloor\frac{m}{R}\rfloor} R=1n(TRFTμ(TR))Rn×Rm
预处理一下
∏T∣RFTμ(RT) \prod_{T|R}F_T^{\mu(\frac{R}{T})} TRFTμ(TR)
然后数论分块即可。
code:code:code:

#include <bits/stdc++.h>
#define int long long
#define regi register int
#define mod 1000000007
int T,n,m;
int vis[1000001],prime[1000001],mu[1000001],fi[1000001],power[1000001];
int tot;
inline int read(){
    int r=0,w=0,c;
    for(;!isdigit(c=getchar());r=c);
    for(w=c^48;isdigit(c=getchar());w=w*10+(c^48));
    return r^45?w:-w;
}
inline int ksm(int x,long long y,long long z=1){
	for(;y;(z*=y&1?1LL*x:1LL*1)%=mod,y>>=1,(x*=x)%=mod);
	return z%mod;
}
main(){
	fi[1]=fi[2]=1;
	for(regi i=3;i<=1000000;++i)
	  fi[i]=(fi[i-1]+fi[i-2])%mod;
	mu[1]=1;
	for(regi i=2;i<=1000000;++i){
		if(!vis[i]){
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(regi j=1;j<=tot&&i*prime[j]<=1000000;++j){
		  vis[i*prime[j]]=1;
		  if(i%prime[j])
		    mu[i*prime[j]]=mu[i]*mu[prime[j]];
		  else{
		  	mu[i*prime[j]]=0;
		    break;
		  }
		}
	}
  for(regi i=0;i<=1000000;++i)
    power[i]=1;
	for(regi i=1;i<=1000000;++i){
		int invfi=ksm(fi[i],mod-2);
		for(regi j=i;j<=1000000;j+=i){
			if(mu[j/i]==-1)
			  (power[j]*=invfi)%=mod;
			else if(mu[j/i]==1)
			  (power[j]*=fi[i])%=mod;
		}
	}
	for(regi i=1;i<=1000000;++i)
	  power[i]=power[i]*power[i-1]%mod;
	T=read();
	while(T--){
		n=read(),m=read();
		if(n>m)
		  std::swap(n,m);
		int ans=1;
		for(regi i=1,j;i<=n;i=j+1){
			j=std::min(n/(n/i),m/(m/i));
			(ans*=ksm(power[j]*ksm(power[i-1],mod-2)%mod,1LL*(n/i)*(m/i)))%=mod;
		}
		printf("%lld\n",ans);
	}
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值