首先计算出所有的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; }
原文地址:http://blog.csdn.net/yanzheshi/article/details/47109353