HDU 4335What is N?2012多校联赛第四场(欧拉函数+坑数据)

本文介绍了一道关于求解特定条件下整数个数的数学竞赛题。通过分析题目要求及给出的样例输入输出,文章提供了详细的解题思路与AC代码实现,并对代码中涉及的重要算法进行了说明。

What is N?

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1030    Accepted Submission(s): 285


Problem Description
  (This problem is really old&easy and any acmer who is good at math may solve it in second)
  As we know, math is both intangible and specific. Today you are going to solve the following math problem:
  Given one non-negative integer b, one positive number P and one positive integer M, how many n could you find to satisfy the following 2 rules?

  Here n! means n factorial , 0!=1,1!=1,2!=2,3!=6…,n!=(n-1)!*n
 

Input
  In the first line of the input , we have one integer T indicating the number of test cases. (1 <= T <= 20)
  Then T cases follows.
  For every case, only 3 integers (b, P and M) in a single line. ( 0<=b<P, 1<=P<=10^5, 1 <= M <=2^64 – 1 )
 

Output
  For each test case, first you should print "Case #x: " in a line, where x stands for the case number started with 1. Then one integer indicates the number of "n" that you can find.
 

Sample Input
  
3 1 2 3 2 3 4 3 4 5
 

Sample Output
  
Case #1: 2 Case #2: 0 Case #3: 0
 

                    题目大意:上面有个公式,求满足条件的个数。开始看会想到一个降幂公式:A^x = A^(x % Phi(C) + Phi(C)) (mod C)不过用这个公式需要一个条件 x>=Phi(C)

       解题思路:根据A^x = A^(x % Phi(C) + Phi(C)) (mod C)找到n!%phi(p)==0的临界值,那么就直接转换成n^phi(p)%p,前面的算第一部分,找到临界值后就很简单了,求第二部分,直接利用鸽笼原理循环节算一个循环内的即可。  还有就是p==1&&b==0需要特判,答案应该是m+1但是可能会爆int64所以需要特判,详见代码。

            题目地址:What is N?

AC代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
using namespace std;

__int64 b,p,m;
__int64 geteular(__int64 n)
{
    __int64 m=sqrt(n+0.5),ans=n,i;
    for(i=2;i<=m;i++)
        if(n%i==0)
        {
            ans=ans/i*(i-1);
            while(n%i==0)
                n/=i;
        }
    if(n>1)
        ans=ans/n*(n-1);
    return ans;
}

__int64 powmo(__int64 a,__int64 b)
{
    __int64 ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    return ans;
}

int main()
{
    int tes,cas=0;
    scanf("%d",&tes);
    while(tes--)
    {
        scanf("%I64u%I64u%I64u",&b,&p,&m);
        printf("Case #%d: ",++cas);
        if(p==1&&b==0)  //全部都符合条件的时候
        {
            //要注意溢出,现场赛过了的人真心厉害!
            if(m==18446744073709551615ULL)
                printf("18446744073709551616\n");
              else
                printf("%I64u\n",m+1);
            continue;
        }

        __int64 phi=geteular(p),fac=1,res=0;
        int num,add=0;
        for(int i=0;i<=p;i++)
        {
            if(fac>=phi) add=phi;
            fac%=phi;
            if(fac==0){num=i;break;} //找到n!%phi==0的临界值
            if(powmo(i,fac+add)==b)
                    res++;
            fac*=i+1;
        }
        //n!%phi(p)=0的时候,其实就是求n^phi(p)%p
        for(int i=num;i<num+p&&i<=m;i++) //一个循环里面找
        {
            if(powmo(i,phi)==b)
                res+=(m-i)/p+1;   //根据鸽巢原理余数是循环的
        }
        printf("%I64u\n",res);
    }
    return 0;
}


下面是__int64 int 等表示的范围
unsigned   int   0~4294967295   
int     2147483648~2147483647 
unsigned long 0~4294967295
long   2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:1844674407370955161
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值