HDU 3641 Treasure Hunting

数论的题做的很少,这道题本来不难,结果在五个小时内还是没做出来。所有a[i]分解质因子,并累计0到100中所有质因子出现的次数存入num数组中。X!要能被M整除,那么在M中出现的所有的质因子就应该在x!中出现并且出现的次数不少于在M中出现的次数。然后二分答案。

有一个计算公式:

LL cal(LL i, LL x)

{

    LL ret = 0;

    while(x)

    {

        x /= i;

        ret += x;

    }

    return ret;

}

可以求出i在X!中出现的次数。

/*Accepted    3641    0MS    252K    1461 B    C++    Yu*/

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<algorithm>

using namespace std;



typedef __int64 LL;

const int MAXN = 105;

LL a, b, ans;

LL num[MAXN];

int n;

void pre(LL a, LL b)

{

    int i, cnt;

    for(i = 2; i * i <= a; i ++)

    {

        cnt = 0;

        while(a % i == 0)

        {

            a /= i;

            cnt ++;

        }

        num[i] += cnt * b;

        if(a == 1) break;

    }

    if(a > 1) num[a] += b; //此时,a是素数

}



LL cal(LL i, LL x)

{

    LL ret = 0;

    while(x)

    {

        x /= i;

        ret += x;

    }

    return ret;

}



bool judge(LL x)

{

    int i;

    for(i = 1; i <= 100; i ++)

    {

        if(num[i])

        {

            LL t = cal(i, x);

            if(t < num[i])

                return false;

        }

    }

    return true;

}



int main()

{

    int T, i;

    scanf("%d", &T);

    while(T --)

    {

        scanf("%d", &n);

        memset(num, 0, sizeof num);

        for(i = 0; i < n; i ++)

        {

            scanf("%I64d%I64d", &a, &b);

            pre(a, b);

        }

        LL left = 0, right = (LL(1)) << 60;

        while(left <= right)

        {

            LL mid = (left + right) >> 1;

            if(judge(mid))

            {

                ans = mid;

                right = mid - 1;

            }

            else left = mid + 1;

        }

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

    }

    return 0;

}

 

 

你可能感兴趣的:(HDU)