t组数据 给定N和M
求解GCD(1, 1) * GCD(1, 2) * ... * GCD(1, M) * GCD(2, 1) * GCD(2, 2) * ... * GCD(2, M) * ... * GCD(N, 1) * GCD(N, 2) * ... * GCD(N, M).
(1 <= n, m <= 10000000) (1 <= t <= 5).
不要陷入误区,求的是gcd,可以是合数,但这个合数必然可以分解为质数相乘,所以最后的答案也一定可以转化成素数相乘,那么我们考虑每个素数的指数。
求解gcd(2 * pk, j), 当j是2的倍数时gcd可分解质因数中含有2.那么我们考虑会出现多少个2。可以联想求解n!末尾有多少个0,就会知道这里应该是
(N / 2) * (M / 2) + (N / 4) * (M /4) + ... + (N / 2k) * (M / 2k) (2k <= min(N, M))
打素数的表, 然后求解每个素数的指数,快速幂取模
#include <cstdio> #define MOD 1000000007 using namespace std; typedef long long LL; int N, M; const int maxn = 10000000 + 10; bool is_prime[maxn]; int prime[1000000]; void get_prime() { for (int i = 0; i < maxn; i++) is_prime[i] = true; is_prime[0] = is_prime[1] = false; for (int i = 2; i < maxn; i++) { if (is_prime[i]) { prime[++prime[0]] = i; } for (int j = i + i; j < maxn; j += i) is_prime[j] = false; } } LL qpow(LL x, LL n) { LL res = 1; while (n > 0) { if (n & 1) res = res * x % MOD; x = x * x % MOD; n >>= 1; } return res; } void solve() { LL ans = 1; int small = min(N, M); for (LL i = 1; i <= prime[0] && prime[i] <= small; i++) { LL num = prime[i]; LL tmp = 0; while (num <= small) { tmp += (LL)(N / num) * (M / num); num *= prime[i]; //digit++; } ans *= qpow(prime[i], tmp); ans = ans % MOD; } printf("%lld ", ans); } int main(int argc, const char * argv[]) { get_prime(); int T; scanf("%d", &T); while (T--) { scanf("%d%d", &N, &M); solve(); } return 0; }