SPOJ PROD1GCD - Product it again

SPOJ PROD1GCD

Description
he problem is very simple. given two integers n and m, find the product 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).

Input
The first line will be the number of test cases t, followed by t lines , each having two numbers n and m (1 <= n, m <= 10000000) (1 <= t <= 5).

Output
Output the required solution modulo 10^9+7.

Example
Input
1
5 6
Output
5760

题意:给出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)。

思路:某人告诉我,找规律,统计质数就行。

考虑某一个质数p对答案的贡献为p^((n/p * m/p) + ((n/p^2 * m/p^2)) + ….)
原理类比n!的质因子分解后,对某个质因子p的指数大小的计数。
所以我们只需要一个线性筛即可,然后暴力计数。

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long LL;
const LL mod = 1e9+7;
const LL maxn = 10000000 + 5;
bool vis[maxn]; //标记是否访问过某个数
LL p[maxn/10]; //记录最大范围内的所有素数
LL cnt;

void GetPrime()//找出最大范围内的所有素数
{
    memset(vis,0,sizeof(vis));
    cnt = 0;
    for(LL i = 2; i < maxn; i++){
        if(!vis[i]){
            p[cnt++] = i;
        }
        for(LL j = 0; j < cnt && p[j] * i < maxn; j++){
            vis[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

LL Pow(LL a, LL b)
{
    LL res = 1;
    while(b) {
        if(b & 1) {
            res *= a;
            res %= mod;
        }
        a *= a;
        a %= mod;
        b >>= 1;
    }
    return res;
}

int main()
{
    GetPrime();
    LL t,n,m;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        LL res = 1;
        if(n > m) swap(n, m);

        for(LL i = 0 ;i < cnt && p[i] <= n; i++){
            LL tmp = p[i];
            LL pn = 0;
            while(tmp <= n){ //求p[i]的指数
                pn += (n/tmp) * (m/tmp);
                tmp *= p[i];
            }
            res *= Pow(p[i], pn);
            res %= mod;
        }
        printf("%lld\n",res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值