[SDOI2017] 数字表格

反演拾遗,设'~'表示min(n,m),推狮子

\[\prod_{i=1}^n\prod_{j=1}^n\mathbb{fib}_{\gcd(a,b)} =\prod_{d=1}^\sim\mathbb{pow}(\mathbb{fib}_d,\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\epsilon(\gcd(n,m)))\\ =\prod_{d=1}^\sim\mathbb{pow}(\mathbb{fib}_d,\sum_{t=1}^{\sim/d}\mu(t)\frac{n}{dt}\frac{m}{dt})\\ =\prod_{q=1}^\sim\prod_{d|q}\mathbb{pow}(\mathbb{fib}_d,\mu(\frac{q}{d})\frac{n}{q}\frac{m}{q})\\ =\prod_{q=1}^\sim\mathbb{pow}(\prod_{d|q}\mathbb{pow}(\mathbb{fib}_d,\mu(\frac{q}{d})),\frac{n}{q}\frac{m}{q}) \]

预处理处外层pow的底数设为w[q],求其前缀积,每组询问分块。

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const int N=1e6+10;
const int P=1e9+7;

inline int qpow(LL x,LL y) {
	int c=1;
	for(; y; y>>=1,x=x*x%P) 
		if(y&1) c=x*c%P;
	return c;
}

int pri[N],mu[N],fib[N],fiv[N],cnt;
long long w[N];
bool vis[N];

void initial() {
	mu[1]=1;
	for(int i=2; i<N; ++i) {
		if(!vis[i]) pri[++cnt]=i,mu[i]=-1;
		for(int j=1; j<=cnt&&i*pri[j]<N; ++j) {
			vis[i*pri[j]]=1;
			if(i%pri[j]==0) break;
			else mu[i*pri[j]]=-mu[i];
		}
	}
	fib[1]=w[0]=w[1]=fiv[0]=fiv[1]=1;
	for(int i=2; i<N; ++i) {
		fib[i]=(fib[i-1]+fib[i-2])%P;
		fiv[i]=qpow(fib[i],P-2);
		w[i]=1;
	}
	for(int d=1; d<N; ++d) {
		for(int q=d; q<N; q+=d) {
			if(mu[q/d]>0) w[q]=w[q]*fib[d]%P;
			else if(mu[q/d]<0) w[q]=w[q]*fiv[d]%P;
		}
		w[d]=w[d-1]*w[d]%P;
	}
}
int main() {
	initial(); //0.32s
	int T,n,m; 
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&m);
		int c=1,sim=min(n,m);
		for(int l=1,r; l<=sim; l=r+1) {
			r=min(n/(n/l),m/(m/l));
			c=1LL*c*qpow(w[r]*qpow(w[l-1],P-2)%P,1LL*n/l*(m/l)%(P-1))%P;
		}
		printf("%d\n",c);
	}
	return 0;
}

\(\mu\)求成\(\varphi\)是要闹哪样啊

posted @ 2019-04-01 16:42  nosta  阅读(201)  评论(0编辑  收藏  举报