您的位置:首页 > 编程语言 > C语言/C++

GCD

2016-06-22 16:15 411 查看

题目描述

Given an integer N and M, you have to calculate



Here GCD(N,K) means the greatest common divisor of integer N and integer K

.

输入

The first line contains a single integer T(1≤T≤10), indicating the number of test cases.

Each test case contains two integers N and M (1≤N,M≤109).

输出

Output the required answer modulo 109+7 for each test case, one per line.

样例输入

2

4 2

2 5

样例输出

24

30

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

#define M 1000000007
#define LL long long

int a[1024], b[1024];
int num, num1;

void gcd(int n) {
num = 0;
for (int i = 1; i <= sqrt(n); ++i) {
if ((n % i) == 0) {
a[num++] = i;
a[num++] = n / i;
if (n / i == i)
num--;
}
}
sort(a,a + num);
num1 = n;
for (int i = num-1; i >= 0; --i) {
b[i] = n/a[i];
for (int j = num-1; j > i ; --j) {
if(a[j] % a[i] == 0)
b[i] -= b[j];
}
num1 -= b[i];
}
}

LL test(LL m, int gcd) {
LL sum = 1;
while(gcd){
if(gcd % 2 == 1)
sum = (sum * m) % M;
m = (m * m) % M;
gcd >>= 1;
}
sum = sum % M;
return sum;
}

int main()
{
int t, n;
LL s, m;
cin >> t;
while (t--) {
cin >> n >> m;
if (n == 1){
printf("%lld\n",m);
continue;
}
s = 0;
num1 = 1;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
gcd(n);
for (int i = 0; i < num; ++i) {
//cout << a[i] << ", " << b[i] << endl;
s = (s + b[i] * test(m, a[i])) % M;
}
//cout << num1 << endl;
s = (s + m * (num1)) % M;
s = s % M;
printf("%lld\n",s);
}
return 0;
}


这道题逻辑是很简单的,但是按着最普通的方法做,你都不知道到超时多久了,所以得用特殊的方法。这里有幂,我们就用快速幂的方法。还有大数求最大公约数,我之前用的是辗转相除法,一直到10000000就不行了,时间超过了1s。后来用了遍历求约数的方法,结果到1000000000大概要3s,真的是醉了。最后在遍历的基础上,做了些剪枝,然后速度快得飞起~。
其实辗转相除法是算比较快的了,只不过这里的题目要有好多次求最大公约数,所以这里不适合。先求约数的方法显然更适合这种方法。


在做题目的时候翻到一个不错的讲GDC的博客

http://www.cnblogs.com/zhangshu/archive/2011/07/20/2111276.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 算法