「SDOI2017」数字表格

题目链接


问题分析

[egin{aligned} Ans&=prod_{i=1}^nprod_{j=1}^mf[gcd(i,j)]\ &=prod_{t=1}^nf(t)^{sumlimits_{i=1}^nsumlimits_{j=1}^m[gcd(i,j)=t]}\ &=prod_{t=1}^nf(t)^{sumlimits_{t|d}^nmu(frac{d}{t})lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor}\ &=prod_{t=1}^nprod_{t|d}f(t)^{mu(frac{d}{t})lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor}\ &=prod_{d=1}^nprod_{t|d}f(t)^{mu(frac{d}{t})lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor}\ &=prod_{d=1}^{n}[prod_{t|d}f(t)^{mu(frac{d}{t})}]^{lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor} end{aligned} ]

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

(f(t)=sumlimits_{i=1}^nsumlimits_{j=1}^m[gcd(i,j)=t])。设(F(t)=sumlimits_{i=1}^nsumlimits_{j=1}^m[t|gcd(i,j)]=lfloorfrac{n}{t} floorlfloorfrac{m}{t} floor)

因为(F(t)=sumlimits_{t|d}f(d)),所以(f(t)=sumlimits_{t|d}mu(frac{d}{t})F(d)=sumlimits_{t|d}mu(frac{d}{t})lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor)

最后的式子中,中括号内的东西可以(O(nlog n))预处理。然后对于每个询问进行整除分块。如果不考虑快速幂,时间复杂度就是(O(Tsqrt n+nlog 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
", Ans );
	return;
}

int main() {
	Init();
	int TestCases;
	scanf( "%d", &TestCases );
	for( ; TestCases--; ) Work();
	return 0;
}
原文地址:https://www.cnblogs.com/chy-2003/p/10559345.html