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

来源:互联网 发布:个人域名是什么样的 编辑:程序博客网 时间:2024/05/16 01:44

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
31 2 32 3 43 4 5
 

Sample Output
Case #1: 2Case #2: 0Case #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~4294967295long   2147483648~2147483647long long的最大值:9223372036854775807long long的最小值:-9223372036854775808unsigned long long的最大值:1844674407370955161__int64的最大值:9223372036854775807__int64的最小值:-9223372036854775808unsigned __int64的最大值:18446744073709551615


原创粉丝点击