首先计算出所有的f,这里容易超时,注意优化:先计算出所有质数,然后在利用这些质数去求f。 易知f中的最大值为7,然后用一个数组b[i][j]记录f[1]到f[i]中有多少个j(j 为1到7),这个用递推可得。 那么如果给定区间L, R, 则f[R][j] - f[L - 1][j]可算出1到7各出现了多少次, 根据这些次数就可以找出最大公约数了。代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 1000002;
int prime[MAXN + 1], f[MAXN], b[MAXN][8], bb[8];;
void getprime() //先计算区间内的所有质数,提高计算效率。
{
memset(prime, 0, sizeof(prime));
for(int i = 2; i <= MAXN; i++)
{
if(!prime[i]) prime[++prime[0]] = i;
for(int j = 1; j <= prime[0] && prime[j] <= MAXN/ i; j++)
{
prime[prime[j] * i] = 1;
if(i % prime[j] == 0) break;
}
}
}
int getFactors(int tmp) //计算质因子的个数。
{
int fatCnt = 0;
for(int i = 1; prime[i] <= tmp/prime[i]; i++)
{
if(tmp % prime[i] == 0)
{
while(tmp % prime[i]== 0)
tmp /= prime[i];
fatCnt++;
}
}
if(tmp != 1)
{
fatCnt++;
}
return fatCnt;
}
int gcd(int a, int b)
{
while(b != 0)
{
int tem = a % b;
a = b;
b = tem;
}
return a;
}
int getAns() //根据区间中f值的情况输出结果。
{
int i, j, ans = 1;
for(i = 7; i >= 1; i--)
{
if(!bb[i])
continue;
for(j = i; j >= 1; j--)
{
if(j == i)
{
if(bb[i] > 1)
ans = max(ans, j);
continue;
}
if(bb[j] >= 1)
ans = max(ans, gcd(i, j));
}
}
return ans;
}
int main()
{
int i, j;
getprime();
for(i = 2; i <= MAXN; i++)
f[i] = getFactors(i);
for(i = 2; i <= MAXN; i++)
{
for(j = 1; j <= 7; j++)
b[i][j] = b[i-1][j];
b[i][f[i]]++;
}
int l, r, t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &l, &r);
memset(bb, 0, sizeof(bb));
for(i = 1; i <= 7; i++)
{
bb[i] = b[r][i] - b[l-1][i]; //bb记录区间内f值的情况。
}
printf("%d\n", getAns());
}
return 0;
}