洛谷 P3704 [SDOI2017]数字表格(莫比乌斯函数)

题面传送门

题意:

\[\prod\limits_{i=1}^n\prod\limits_{j=1}^mfib_{\gcd(i,j)} \]

\(T\) 组测试数据,\(1 \leq T \leq 10^3\)\(1 \leq n,m \leq 10^6\)

没啥好说的,直接推式子。

\[\begin{aligned}ans&=\prod\limits_{i=1}^n\prod\limits_{j=1}^mfib_{\gcd(i,j)}\\&=\prod\limits_{d=1}^{\min(n,m)}\prod\limits_{i=1}^n\prod\limits_{j=1}^mfib_d\times[\gcd(i,j)=d]\\&=\prod\limits_{d=1}^{\min(n,m)}fib_d^{\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]}\end{aligned} \]

设指数上的那一大堆玩意儿为 \(M\),那么

\[\begin{aligned}M&=\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]\\&=\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum\limits_{p|\gcd(i,j)}\mu(p)\\&=\sum\limits_{p=1}^{\lfloor\frac{\min(n,m)}{d}\rfloor}\mu(p)\times\lfloor\frac{n}{dp}\rfloor\lfloor\frac{m}{dp}\rfloor\end{aligned} \]

\[\begin{aligned}ans&=\prod\limits_{d=1}^{\min(n,m)}fib_d^M\\&=\prod\limits_{d=1}^{\min(n,m)}fib_d^{\sum\limits_{p=1}^{\lfloor\frac{\min(n,m)}{d}\rfloor}\mu(p)\times\lfloor\frac{n}{dp}\rfloor\lfloor\frac{m}{dp}\rfloor}\\&=\prod\limits_{t=1}^{\min(n,m)}\prod\limits_{d|t}fib_d^{\mu(\frac{t}{d})\times\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor}\\&=\prod\limits_{t=1}^{\min(n,m)}(\prod\limits_{d|t}fib_d^{\mu(\frac{t}{d})})^{\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor}\end{aligned} \]

把括号里的东西预处理出来然后整除分块就行了

/*
Contest: -
Problem: P3704
Author: tzc_wk
Time: 2020.9.16
*/
#include <bits/stdc++.h>
using namespace std;
#define fi			first
#define se			second
#define pb			push_back
#define fz(i,a,b)	for(int i=a;i<=b;i++)
#define fd(i,a,b)	for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a)		a.begin(),a.end()
#define fill0(a)	memset(a,0,sizeof(a))
#define fill1(a)	memset(a,-1,sizeof(a))
#define fillbig(a)	memset(a,0x3f,sizeof(a))
#define y1			y1010101010101
#define y0			y0101010101010
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
inline int read(){
	int x=0,neg=1;char c=getchar();
	while(!isdigit(c)){
		if(c=='-') neg=-1;
		c=getchar();
	}
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return x*neg;
}
const int MOD=1e9+7;
inline int qpow(int x,int e){
	if(!x) return 1;
	int ans=1;
	while(e){
		if(e&1) ans=ans*x%MOD;
		x=x*x%MOD;e>>=1;
	}
	return ans;
}
int f[1000005],mu[1000005],p[1000005],pcnt=0,F[1000005];
bool vis[1000005];
inline void prework(int n){
	f[1]=f[2]=1;
	for(int i=3;i<=n;i++)
		f[i]=(f[i-1]+f[i-2])%MOD;
	mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){p[++pcnt]=i;mu[i]=-1;}
		for(int j=1;j<=pcnt&&p[j]*i<=n;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
			mu[i*p[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++) F[i]=1;
	for(int i=1;i<=n;i++){
		int inv=qpow(f[i],MOD-2);
		for(int j=i;j<=n;j+=i){
			if(!mu[j/i]) continue;
			else if(~mu[j/i]) F[j]=F[j]*f[i]%MOD;
			else F[j]=F[j]*inv%MOD;
		}
	}
	for(int i=2;i<=n;i++)
		F[i]=F[i-1]*F[i]%MOD;
}
signed main(){
	prework(1e6);
	int T=read();
	while(T--){
		int n=read(),m=read(),ans=1;
		for(int l=1,r;l<=min(n,m);l=r+1){
			r=min(n/(n/l),m/(m/l));
			ans=(ans*(qpow(F[r]*qpow(F[l-1],MOD-2)%MOD,(n/l)*(m/l)%(MOD-1))))%MOD;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2020-09-16 21:32  tzc_wk  阅读(162)  评论(1)    收藏  举报