程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU 4335 What is N? 多校4(數論)

HDU 4335 What is N? 多校4(數論)

編輯:C++入門知識

大意找出多少個N滿足下式

范圍如此之大啊。結果做法是暴力,囧。
要用到一個降冪公式
A^x = A^(x % Phi(C) + Phi(C)) (mod C) (x>=Phi(C))
注意括號裡的條件,那麼當n比較小的時候,就不能用這個了,n比較小,肯定是暴力嘛。

那麼第一個階段便是當n比較小,n!小於phi(p),直接暴力求解。

當n!大於phi(P)的時候,便 可以用上面的降冪公式。還得繼續暴力,發現n!%phi(p)會出現0,這是必然的,至少n>=phi(p)為0

那麼(n+1)!%phi(p)也為0,這便出現了重復,轉變為n^(phi(p))%p==b的問題了。固定了指數,根據鴿巢原理,余數是循環的,那麼只

要找出p個的結果,之後通過循環節求解便可以了。

當P為1的時候,b為0,這時候答案是m+1,不過m可能為2^64-1,如果加1的話就溢出了,這裡太坑了

[cpp] 
#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<queue> 
#include<vector> 
#include<cmath> 
#define LL unsigned long long 
//#define MOD 1000000007 
#define eps 1e-6 
#define zero(a)  fabs(a)<eps 
using namespace std; 
LL get_eular(LL m){ 
    LL ret=1; 
    for(LL i=2;i*i<=m;i++) 
        if(m%i==0){ 
            ret*=i-1; 
            m/=i; 
            while(m%i==0){ 
                m/=i; 
                ret*=i; 
            } 
        } 
    if(m>1) 
        ret*=m-1; 
    return ret; 

LL PowMod(LL a,LL b,LL MOD){ 
    LL ret=1; 
    while(b){ 
        if(b&1) 
            ret=(ret*a)%MOD; 
        a=(a*a)%MOD; 
        b>>=1; 
    } 
    return ret; 

LL b,p,m,ring[100005]; 
int main(){ 
    int t,cas=0; 
    scanf("%d",&t); 
    while(t--){ 
        scanf("%I64u%I64u%I64u",&b,&p,&m); 
        printf("Case #%d: ",++cas); 
        if(p==1){ 
            //大坑一個,要注意溢出 
            if(m==18446744073709551615ULL) 
                printf("18446744073709551616\n");        
            else                 
                printf("%I64u\n",m+1); 
            continue; 
        } 
        LL i=0,phi=get_eular(p),fac=1,ans=0; 
        //第一個環節,n!<phi(p) 
        for(i=0;i<=m&&fac<=phi;i++){ 
            if(PowMod(i,fac,p)==b) 
                ans++; 
            fac*=i+1; 
        } 
        fac=fac%phi; 
        //第二個環節,n^(n!%phi(p)+phi(p)),直到指數固定為phi(p) 
        for(;i<=m&&fac;i++){ 
            if(PowMod(i,fac+phi,p)==b) 
                ans++; 
            fac=(fac*(i+1))%phi; 
        } 
        if(i<=m){ 
            LL cnt=0; 
            //打表一個循環 
            for(int j=0;j<p;j++){ 
                ring[j]=PowMod(i+j,phi,p); 
                if(ring[j]==b) 
                    cnt++; 
            } 
            LL idx=(m-i+1)/p; 
            ans+=cnt*idx; 
            LL remain=(m-i+1)%p; 
            for(int j=0;j<remain;j++) 
                if(ring[j]==b) 
                    ans++; 
        } 
        printf("%I64u\n",ans); 
    } www.2cto.com
    return 0; 

 作者:ACM_cxlove

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved