SDOI 2017 数字表格 题解

题目传送门

题目大意: ∏ i = 1 a ∏ j = 1 b p ( gcd ⁡ ( i , j ) ) \prod _{i=1}^a \prod _{j=1}^b p(\gcd(i,j)) i=1aj=1bp(gcd(i,j)),其中 p p p 是斐波那契数列。

题解

s ( d ) s(d) s(d) 表示满足 gcd ⁡ ( i , j ) = d \gcd(i,j)=d gcd(i,j)=d i , j i,j i,j 的数量, F ( n ) F(n) F(n) 表示满足 n ∣ gcd ⁡ ( i , j ) n|\gcd(i,j) ngcd(i,j) i , j i,j i,j 的数量,那么有:
F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d}f(d) F(n)=ndf(d)

根据莫比乌斯反演,有:
f ( d ) = ∑ d ∣ n F ( n ) μ ( n d ) f(d)=\sum_{d|n}F(n)\mu(\frac nd) f(d)=dnF(n)μ(dn)

大力推柿子:
∏ i = 1 a ∏ j = 1 b p ( gcd ⁡ ( i , j ) ) = ∏ i = 1 min ⁡ ( a , b ) p ( i ) f ( i ) = ∏ i = 1 min ⁡ ( a , b ) p ( i ) ∑ i ∣ d F ( d ) μ ( d i ) \prod _{i=1}^a \prod _{j=1}^b p(\gcd(i,j))\\ =\prod_{i=1}^{\min(a,b)} p(i)^{f(i)}\\ =\prod_{i=1}^{\min(a,b)} p(i)^{\sum_{i|d}F(d)\mu(\frac d i)} i=1aj=1bp(gcd(i,j))=i=1min(a,b)p(i)f(i)=i=1min(a,b)p(i)idF(d)μ(id)

显然有 F ( n ) = ⌊ a n ⌋ ⌊ b n ⌋ F(n)=\lfloor \frac a n \rfloor \lfloor \frac b n \rfloor F(n)=nanb,带进去得:
= ∏ i = 1 min ⁡ ( a , b ) p ( i ) ∑ i ∣ d ⌊ a d ⌋ ⌊ b d ⌋ μ ( d i ) =\prod_{i=1}^{\min(a,b)} p(i)^{\sum_{i|d}\lfloor \frac a d \rfloor \lfloor \frac b d \rfloor\mu(\frac d i)} =i=1min(a,b)p(i)iddadbμ(id)

j = d i j=\frac d i j=id,更换枚举对象,于是有:
= ∏ i = 1 min ⁡ ( a , b ) p ( i ) ∑ j = 1 min ⁡ ( a , b ) i μ ( j ) ⌊ a i j ⌋ ⌊ b i j ⌋ =\prod_{i=1}^{\min(a,b)} p(i)^{\sum_{j=1}^{\frac {\min(a,b)} i} \mu(j)\lfloor \frac a {ij} \rfloor \lfloor \frac b {ij} \rfloor} =i=1min(a,b)p(i)j=1imin(a,b)μ(j)ijaijb

那个 ∑ \sum 是可以弄出来的,变成一个 ∏ \prod
= ∏ i = 1 min ⁡ ( a , b ) ∏ j = 1 min ⁡ ( a , b ) i p ( i ) μ ( j ) ⌊ a i j ⌋ ⌊ b i j ⌋ =\prod_{i=1}^{\min(a,b)}\prod_{j=1}^{\frac {\min(a,b)} i} p(i)^{ \mu(j)\lfloor \frac a {ij} \rfloor \lfloor \frac b {ij} \rfloor} =i=1min(a,b)j=1imin(a,b)p(i)μ(j)ijaijb

根据莫比乌斯反演的一般思想: 两个变量乘在一起是很难看的,比如说里面的 i j ij ij,于是用一个 k k k 代替掉,更换枚举对象,有
= ∏ k = 1 min ⁡ ( a , b ) ∏ j ∣ k p ( k j ) μ ( j ) ⌊ a k ⌋ ⌊ b k ⌋ = ∏ k = 1 min ⁡ ( a , b ) ( ∏ j ∣ k p ( k j ) μ ( j ) ) ⌊ a k ⌋ ⌊ b k ⌋ =\prod_{k=1}^{\min(a,b)} \prod_{j|k} p(\frac k j)^{\mu(j)\lfloor \frac a k \rfloor \lfloor \frac b k \rfloor}\\ =\prod_{k=1}^{\min(a,b)} \left(\prod_{j|k} p(\frac k j)^{\mu(j)}\right)^{\lfloor \frac a k \rfloor \lfloor \frac b k \rfloor}\\ =k=1min(a,b)jkp(jk)μ(j)kakb=k=1min(a,b)jkp(jk)μ(j)kakb

S ( n ) = ∏ d ∣ n p ( n d ) μ ( d ) S(n)=\prod_{d|n} p(\frac n d)^{\mu(d)} S(n)=dnp(dn)μ(d),那么柿子变成:
= ∏ k = 1 min ⁡ ( a , b ) S ( k ) ⌊ a k ⌋ ⌊ b k ⌋ =\prod_{k=1}^{\min(a,b)}S(k)^{\lfloor \frac a k \rfloor \lfloor \frac b k \rfloor}\\ =k=1min(a,b)S(k)kakb

因为 μ ( d ) \mu(d) μ(d) 只有三种取值: − 1 , 0 , 1 -1,0,1 1,0,1 ,所以 S S S 是可以快速地预处理的。

然后除法分块即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1000010
#define ll long long
#define mod 1000000007

int T,n,m;
int prime[maxn],t=0;
bool v[maxn];
int mu[maxn];
ll f[maxn],S[maxn];
ll ksm(ll x,ll y)
{
	ll re=1,tot=x;
	while(y>0)
	{
		if(y%2==1)re=re*tot%mod;
		tot=tot*tot%mod;
		y/=2;
	}
	return re;
}
ll inv(ll x){return ksm(x,mod-2);}
void work()
{
	mu[1]=1;
	for(int i=2;i<=maxn-10;i++)//线性筛mu
	{
		if(!v[i])prime[++t]=i,mu[i]=-1;
		for(int j=1;j<=t&&i*prime[j]<=maxn-10;j++)
		{
			v[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
	f[1]=f[2]=1;
	S[0]=S[1]=S[2]=1;
	for(int i=3;i<=maxn-10;i++)
	f[i]=(f[i-1]+f[i-2])%mod,S[i]=1;//预处理斐波那契数列
	
	for(int i=1;i<=maxn-10;i++)
	for(int j=i;j<=maxn-10;j+=i)
	if(mu[j/i]==-1)S[j]=S[j]*inv(f[i])%mod;
	else if(mu[j/i]==1)S[j]=S[j]*f[i]%mod;//处理S
	for(int i=1;i<=maxn-10;i++)//求S的前缀积
	S[i]=S[i]*S[i-1]%mod;
}

int main()
{
	work();
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d",&n,&m);
		int l=1,r;
		ll ans=1;
		while(l<=min(n,m))
		{
			r=min(n/(n/l),m/(m/l));
			ans=ans*ksm(S[r]*inv(S[l-1])%mod,(ll)(n/l)*(m/l))%mod;
			l=r+1;
		}
		printf("%lld\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值