原题大意
给出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) 结果mod10^9+7。
算法分析
考虑某一个质数p对答案的贡献ans。ans = p^((n/p m/p) + ((n/p^2 m/p^2)) + ….)原理类比n!的质因子分解后,对某个质因子p的指数大小的计数。所以我们只需要一个线性筛即可,然后暴力计数。复杂度约为O((n/logn) logn logn)。
这里有关于n!质因子分解和素数快速筛法的相关博客:
http://www.doc88.com/p-9159772516121.html
程序代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 10000050;
int t,cnt;
ll n,m,p[maxn],ans;
bool tag[maxn];
void getprime(){
cnt = 0;
for(int i = 2; i < maxn; i++){
if(!tag[i])
p[cnt++] = i;
for(int j = 0; j < cnt && i*p[j] < maxn;j++)
{
tag[i*p[j]] = 1;
if(!(i%p[j])) break;
}
}
}
ll pow(ll a, ll b){
ll ans = 1;
while(b){
if(b & 1) ans = ans * a % mod;
a = a*a%mod;
b>>=1;
}
return ans;
}
ll getcnt(ll p, ll limm, ll limn){
ll cnt1 = 0;
ll nex = p;
while(nex <= min(limm,limn)){
cnt1 += (limm/nex) * (limn/nex);
nex *= p;
}
return cnt1;
}
int main(){
memset(tag,false,sizeof(tag));
getprime();
scanf("%d", &t);
while(t--){
scanf("%lld%lld", &n, &m);
ans = 1;
for(int i = 0; i < cnt && p[i] <= min(n,m); i++)
ans = ans * pow(p[i],getcnt(p[i],m,n)) % mod;
printf("%lld\n", ans);
}
return 0;
}