Luogu3704 数字表格

Arahc 11.0

题面

简化题意

多组数据,每组数据给定 n,mn,m,求:

i=1nj=1mfibgcd(i,j)\prod_{i=1}^n \prod_{j=1}^m fib_{\gcd(i,j)}

其中 fibifib_i 表示斐波那契第 ii 项,fib1=fib2=1fib_1=fib_2=1

n,m106,T103n,m\leq 10^6,T\leq 10^3

题解

不失一般性,设 n<mn<m

不妨考虑数列第 ii 项能产生多少贡献,答案可以写为:

k=1nfibii=0nj=0m[gcd(i,j)=k]\prod_{k=1}^n fib_i^{\sum_{i=0}^n \sum_{j=0}^m [\gcd(i,j)=k]}

先把指数提出来处理一下:

i=0nj=0m[gcd(i,j)=k]\sum_{i=0}^n \sum_{j=0}^m [\gcd(i,j)=k]

莫反老套路了吧,中间过程省略:

d=1nkμ(d)nkdmkd\prod_{d=1}^{\lfloor \frac{n}{k} \rfloor} \mu(d) \left\lfloor \frac{n}{kd} \right\rfloor \left\lfloor \frac{m}{kd} \right\rfloor

带回去:

k=1nfibkd=1nkμ(d)nkdmkd\prod_{k=1}^n fib_k^{\sum_{d=1}^{\lfloor \frac{n}{k} \rfloor} \mu(d) \lfloor \frac{n}{kd} \rfloor \lfloor \frac{m}{kd} \rfloor}

然后考虑把指数整理一下:

k=1n(fibkd=1nkμ(d))nkdmkd\prod_{k=1}^n \left( fib_k^{\sum_{d=1}^{\lfloor \frac{n}{k} \rfloor} \mu(d)} \right)^{\lfloor \frac{n}{kd} \rfloor \lfloor \frac{m}{kd} \rfloor}

里面的内容,实际上就是 d=1nkμ(d)\sum_{d=1}^{\lfloor \frac{n}{k} \rfloor} \mu(d) 这么多个 fibkfib_k 相乘,莫反老套路,设 p=kdp=kd

k=1n(kpfibkμ(pk))npmp\prod_{k=1}^n \left( \prod_{k\mid p} fib_k^{\mu(\frac{p}{k})} \right)^{\lfloor \frac{n}{p} \rfloor \lfloor \frac{m}{p} \rfloor}

分别考虑括号内和括号外,对于括号外,数论分块即可。

括号内的东西,设:

f(n)=knfibkμ(nk)f(n)=\prod_{k\mid n} fib_k^{\mu(\frac{n}{k})}

直接暴力预处理,用埃式筛即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int max_n=1000006,N=1000000,mod=1000000007;
inline int read(){
int x=0;bool w=0;char c=getchar();
while(c<'0' || c>'9') w|=c=='-',c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
}
inline int mi(int a,int p=mod-2){
int res=1;
while(p){
if(p&1) res*=a,res%=mod;
a*=a,a%=mod,p>>=1;
}
return res;
}

int n,m,f[max_n],fib[max_n],iv[max_n];

bool isp[max_n];
int pr[max_n],cnt,mu[max_n];
inline void init(int n){
memset(isp,1,sizeof(isp)),isp[1]=0,mu[1]=1;
fib[1]=fib[2]=iv[1]=iv[2]=1;
for(register int i=3;i<=n;++i)
fib[i]=(fib[i-1]+fib[i-2])%mod,
iv[i]=mi(fib[i]);
for(register int i=2;i<=n;++i){
if(isp[i]){
pr[++cnt]=i,
mu[i]=-1;
}
for(register int j=1;j<=cnt && i*pr[j]<=n;++j){
isp[i*pr[j]]=0;
if(i%pr[j]==0){
mu[i*pr[j]]=0;
break;
}
mu[i*pr[j]]=-mu[i];
}
}
for(register int i=0;i<=n;++i)
f[i]=1;
for(register int i=1;i<=n;++i) if(mu[i])
for(register int j=i;j<=n;j+=i)
f[j]=f[j]*(mu[i]>0?fib[j/i]:iv[j/i])%mod;
for(register int i=2;i<=n;++i)
f[i]=f[i]*f[i-1]%mod;
}

signed main(){
init(N);
for(register int T=read();T>0;--T){
n=read(),m=read();
if(n>m) n^=m^=n^=m;
int ans=1;
for(register int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
int tmp=f[r]*mi(f[l-1])%mod;
ans=ans*mi(tmp,(n/l)*(m/l)%(mod-1))%mod;
}
write((ans+mod)%mod),putchar('\n');
}
return 0;
}
  • 标题: Luogu3704 数字表格
  • 作者: Arahc
  • 创建于 : 2022-01-21 08:00:00
  • 更新于 : 2023-03-19 06:31:34
  • 链接: https://arahc.github.io/2022/01/21/【题解】Luogu3704-数字表格/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
Luogu3704 数字表格