ACM学习历程—HDU 5317 RGCDQ (数论)

Problem Description
Mr. Hdu is interested in Greatest Common Divisor (GCD). He wants to find more and more interesting things about GCD. Today He comes up with Range Greatest Common Divisor Query (RGCDQ). What’s RGCDQ? Please let me explain it to you gradually. For a positive integer x, F(x) indicates the number of kind of prime factor of x. For example F(2)=1. F(10)=2, because 10=2*5. F(12)=2, because 12=2*2*3, there are two kinds of prime factor. For each query, we will get an interval [L, R], Hdu wants to know maxGCD(F(i),F(j)) (Li<jR)
 

 

Input
There are multiple queries. In the first line of the input file there is an integer T indicates the number of queries.
In the next T lines, each line contains L, R which is mentioned above.

All input items are integers.
1<= T <= 1000000
2<=L < R<=1000000
 

 

Output
For each query,output the answer in a single line.
See the sample for more details.
 

 

Sample Input
2
2 3
3 5
 

 

Sample Output
1
1

 

这个题目比较巧妙。

f(i)求的是i的素数因子个数。

首先需要处理因子个数。这个方法很多。

其实对于一个i来说,由于i最大是1000000,然而当2*3*5*7.....*17这时是最大能在这个范围的。其他数的素数因子数目必然小于这个。也就是f(i)最大是7。

这样只需要查询L到R区间内f(i)分别为1, 2, 3, 4, 5, 6, 7的个数,然后暴力枚举gcd的最大值就可以了。

 

当时人比较二,区间求和直接上了线段树,然后MLE了,然后换成树状数组才AC。。。。

赛后经人提醒才发现,这个完全没有点修改操作,根本不需要使用上述工具。直接用sum数组保存前缀和就可以。然后sum[j] - sum[i-1]就是[i, j]区间的和了。。。

 

不管怎样第一次使用树状数组,还是附上代码。

代码:

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <set>

#include <map>

#include <queue>

#include <string>

#include <algorithm>

#define LL long long



using namespace std;



//GCD

//求最大公约数

//O(logn)

int gcd(int a, int b)

{

    if (b == 0)

    return a;

    else

    return gcd(b, a%b);

}



const int maxN = 1000001;



char f[maxN];

bool b[maxN];

int L, R;



struct Val

{

    int v[8];



    Val()

    {

        memset(v, 0, sizeof(v));

    }

    Val operator+(Val x)

    {

        Val ans;

        for (int i = 1; i <= 7; ++i)

            ans.v[i] = x.v[i] + v[i];

        return ans;

    }

    Val operator-(Val x)

    {

        Val ans;

        for (int i = 1; i <= 7; ++i)

            ans.v[i] = v[i] - x.v[i];

        return ans;

    }

};



Val d[maxN];



int lowbit(int x)

{

    return x&(-x);

}



void add(int pos,Val pls)

{

    while(pos <= maxN)//x最大是N

    {

        d[pos] = d[pos] + pls;

        pos += lowbit(pos);

    }

}



Val sum(int to)

{

    Val s;

    while(to > 0)

    {

        s = s + d[to];

        to -= lowbit(to);

    }

    return s;

}



Val query(int from, int to)

{

    return sum(to) - sum(from - 1);

}



void init()

{

    int m = 1000000;

    memset(f,0,sizeof(f));

    memset(b,0,sizeof(b));

    for (int i = 2; i <= m; i++)

    {

        if (!b[i])

            for(int j = i; j <= m; j = j+i)

            {

                b[j] = 1;

                f[j]++;

            }

    }



    for (int i = 2; i <= m; ++i)

    {

        Val tmp;

        tmp.v[f[i]] = 1;

        add(i, tmp);

    }

}



void work()

{

    Val p = query(L, R);

    int ans = 0;

    for (int i = 1; i <= 7; ++i)

    {

        if (!p.v[i])

            continue;

        p.v[i]--;

        for (int j = i; j <= 7; ++j)

        {

            if (!p.v[j])

                continue;

            ans = max(ans, gcd(i, j));

        }

        p.v[i]++;

    }

    printf("%d\n", ans);

}



int main()

{

    //freopen("test.in", "r", stdin);

    init();

    int T;

    scanf("%d", &T);

    for (int times = 0; times < T; ++times)

    {

        scanf("%d%d", &L, &R);

        work();

    }

    return 0;

}

 

你可能感兴趣的:(ACM)