hdu5317 RGCDQ

首先计算出所有的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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值