[SDOI2017]數字表格-數論

VictoryCzt發表於2018-12-19

題目地址-IN-Luogu


題意簡述

我們定義ff為斐波那契數列,那麼f(0)=0,f(1)=1,f(i)=f(i1)+f(i2)[i2]f(0)=0,f(1)=1,f(i)=f(i-1)+f(i-2)[i\geq2]

T1000T\leq 1000組詢問,每次給定n,m106n,m\leq 10^6詢問下面式子的值在模109+710^9+7後的答案。

i=1nj=1mf(gcd(i,j)) \prod_{i=1}^n\prod_{j=1}^mf(gcd(i,j))


還是莫比烏斯反演的套路,雖然變成了累乘,但是做法還是類似的,我們列舉gcdgcd,然後式子就可以變成(這裡預設nmn\leq m,不滿足則交換):

d=1nf(d)i=1nj=1m[gcd(i,j)=d] \prod_{d=1}^nf(d)^{\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]}

這裡相當於每一個f(d)f(d)都會被乘i=1nj=1m[gcd(i,j)=d]\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]次,f(d)f(d)可以O(n)O(n)預處理,主要是指數還不好處理,所以我們接下來對指數進行反演,可以得到:

i=1ndj=1md[gcd(i,j)=1]=i=1ndj=1mdwi,wjμ(w)=wdμ(dw)ndmd \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)=1] \\=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{w|i,w|j}\mu(w) \\=\sum_{w|d}\mu(\frac{d}{w})\left\lfloor\frac{n}{d}\right\rfloor\left\lfloor\frac{m}{d}\right\rfloor

然後我們將其帶回原式得到:

d=1nf(d)wdμ(dw)ndmd \prod_{d=1}^nf(d)^{\sum_{w|d}\mu(\frac{d}{w})\left\lfloor\frac{n}{d}\right\rfloor\left\lfloor\frac{m}{d}\right\rfloor}

把上面的一個\sum拿下來,可以得到:

d=1n(wdf(d)μ(dw))ndmd \prod_{d=1}^n\left(\prod_{w|d}f(d)^{\mu(\frac{d}{w})}\right)^{\left\lfloor\frac{n}{d}\right\rfloor\left\lfloor\frac{m}{d}\right\rfloor}

然後我們可以O(n(logn+))O(n(logn+快速冪))的預處理(wdf(d)μ(dw))\left(\prod_{w|d}f(d)^{\mu(\frac{d}{w})}\right)函式和其字首積,然後對於外面的數論分塊即可。而對於每次提取中間一段的乘積,我們用逆元將前面的除去即可。

複雜度O(nlogn+Tn)O(nlogn+T\sqrt n)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e6+10;
const ll Mod=1e9+7;
bool vis[M];
int n,m;
ll prime[M],f[M],F[M],mu[M],cnt,inv[M],MAX=1e6;
ll fpow(ll a,ll b){
	ll res=1;
	for(;b;b>>=1,a=(a*a)%Mod){
		if(b&1)res=(res*a)%Mod;
	}
	return res;
}
void init(){
	F[0]=mu[1]=F[1]=f[1]=inv[1]=1;
	inv[0]=mu[0]=1;
	for(int i=2;i<=MAX;i++){
		F[i]=1;
		f[i]=(f[i-1]+f[i-2])%Mod;
		inv[i]=fpow(f[i],Mod-2);
		if(!vis[i]){
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1,v;j<=cnt&&i*prime[j]<=MAX;j++){
			v=i*prime[j];
			vis[v]=1;
			if(!(i%prime[j])){
				break;
			}
			mu[v]=-mu[i];
		}
	}
	for(int i=1;i<=MAX;i++){
		if(!mu[i]) continue;
		for(int j=i;j<=MAX;j+=i){
			if(mu[i]==-1)F[j]=F[j]*inv[j/i]%Mod;
			else F[j]=F[j]*f[j/i]%Mod;
		}
	}
	for(int i=2;i<=MAX;i++)
		F[i]=(F[i]*F[i-1])%Mod;

}
ll solve(){
	if(n>m)swap(n,m);
	ll ans=1;
	for(ll i=1,j;i<=n;i=j+1){
		j=min(n/(n/i),m/(m/i));
		ans=(ans*fpow((F[j]*fpow(F[i-1],Mod-2)%Mod)%Mod,1ll*(n/i)*(m/i)))%Mod;
	}
	return ans;
}
int T;
int main(){
	init();
	for(scanf("%d",&T);T--;){
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve());
	}
	return 0;
}

相關文章