「SDOI2017」数字表格

题目链接


问题分析

\[\begin{aligned} Ans&=\prod_{i=1}^n\prod_{j=1}^mf[\gcd(i,j)]\\ &=\prod_{t=1}^nf(t)^{\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=t]}\\ &=\prod_{t=1}^nf(t)^{\sum\limits_{t|d}^n\mu(\frac{d}{t})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor}\\ &=\prod_{t=1}^n\prod_{t|d}f(t)^{\mu(\frac{d}{t})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor}\\ &=\prod_{d=1}^n\prod_{t|d}f(t)^{\mu(\frac{d}{t})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor}\\ &=\prod_{d=1}^{n}[\prod_{t|d}f(t)^{\mu(\frac{d}{t})}]^{\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor} \end{aligned} \]

其中对\(\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=t]\)进行莫比乌斯反演。

\(f(t)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=t]\)。设\(F(t)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[t|\gcd(i,j)]=\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor\)

因为\(F(t)=\sum\limits_{t|d}f(d)\),所以\(f(t)=\sum\limits_{t|d}\mu(\frac{d}{t})F(d)=\sum\limits_{t|d}\mu(\frac{d}{t})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\)

最后的式子中,中括号内的东西可以\(O(n\log n)\)预处理。然后对于每个询问进行整除分块。如果不考虑快速幂,时间复杂度就是\(O(T\sqrt n+n\log n)\)

参考代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const LL Maxn = 1000010;
const LL N = 1000000;
const LL Mod = 1000000007;
LL Num, Prime[ Maxn ], Vis[ Maxn ], Mu[ Maxn ], F[ Maxn ], G[ Maxn ];

LL Power( LL x, LL y ) {
	if( y == 0 ) return 1LL;
	LL t = Power( x, y >> 1 );
	t = t * t % Mod;
	if( y & 1 ) t = t * x % Mod;
	return t;
}

void Init() {
	F[ 0 ] = 0; F[ 1 ] = 1;
	for( int i = 2; 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 ] ) {
			Mu[ i ] = -1;
			Prime[ ++Num ] = i;
		}
		for( int j = 1; j <= Num && i * Prime[ j ] <= N; ++j ) {
			Vis[ i * Prime[ j ] ] = 1;
			if( i % Prime[ j ] ) break;
			Mu[ i *Prime[ j ] ] = -Mu[ i ];
		}
	}
	for( int i = 0; i <= N; ++i ) G[ i ] = 1;
	for( int i = 1; i <= N; ++i ) {
		for( int j = i; j <= N; j += i ) {
			if( Mu[ j / i ] == 1 ) 
				G[ j ] = G[ j ] * F[ i ] % Mod;
			if( Mu[ j / i ] == -1 )
				G[ j ] = G[ j ] * Power( F[ i ], Mod - 2 ) % Mod;
		}
	}
	for( int i = 1; i <= N; ++i ) G[ i ] = G[ i ] * G[ i - 1 ] % Mod;
	return;
}

void Work() {
	LL n, m;
	LL Ans = 1;
	scanf( "%lld%lld", &n, &m );
	if( n > m ) swap( n, m );
	for( int i = 1, j; i <= n; i = j + 1 ) {
		j = min( ( n / ( n / i ) ), ( m / ( m / i ) ) );
		Ans = Ans * Power( G[ j ] * Power( G[ i - 1 ], Mod - 2 ) % Mod, ( n / i ) * ( m / i ) % Mod ) % Mod;
	}
	printf( "%lld\n", Ans );
	return;
}

int main() {
	Init();
	int TestCases;
	scanf( "%d", &TestCases );
	for( ; TestCases--; ) Work();
	return 0;
}
posted @ 2019-03-19 16:11  chy_2003  阅读(306)  评论(0编辑  收藏  举报