快速冪原理
快速冪顧名思義就是快速計算的方法。
我們用一個栗子來了解其原理。
,首先我們試着用二進制表示n,如n=b1010
n=b10+b1000 即n=2+8
自然有
接着我們這樣想,n的二進制表示每一位都對應着,如果該位爲1則乘到結果中去,否則不乘。
即:
上式很有規律,都利用到。
試想如果我們求出了之後保存這個結果,然後,保存,接着計算。
就可以求出二進制對應的每一位的值,然後再決定是乘0還是1。
這種方法的時間複雜度取決於n的二進制位數,即O(logn)
而從一開始乘到次,這種時間複雜度是O(n)。
快速冪例子
typedef long long ll;
//x^n mod a快速冪方法
ll pow_mod(ll x,ll n, ll mod){
ll res=1;
while(n>0){
if(n&1) res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
例題兩道
POJ3641
Description
Fermat’s theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-a pseudoprimes, have this property for some a. (And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)
Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.
Input
Input contains several test cases followed by a line containing “0 0”. Each test case consists of a line containing p and a.
Output
For each test case, output “yes” if p is a base-a pseudoprime; otherwise output “no”.
#include <iostream>
using namespace std;
typedef long long ll;
//x^n 快速冪方法
ll pow_mod(ll x,ll n, ll mod){
ll res=1;
while(n>0){
if(n&1) res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
bool ispri(long long num)
{
for(int i=2;i*i<num;i++)
if(num%i==0)
return false;
return true;
}
//POJ Pseudoprime numbers
int main(){
while(true){
ll p,a;
cin >> p>>a;
if(p==0 && a==0) break;
ll res=pow_mod(a, p, p);
if(res==a && !ispri(a))
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
}
return 0;
}
POJ1995
Description
人是不同的。有些人偷偷看充滿了有趣的女孩的雜誌,有些人在地窖裏製造原子彈,有些人喜歡使用WINDOWS,有些人喜歡數學遊戲。最新的市場調查顯示,這一細分市場目前被低估了,而且缺乏這樣的遊戲。這種遊戲因此被納入了科科達克運動。運動的遵循的規則:
每個玩家選擇兩個數字Ai和Bi,並把它們寫在一張紙條上。其他人看不到這些數字。在一個特定的時刻,所有的玩家都會向其他玩家展示他們的數字。目標是確定包括自己在內的所有玩家的所有表達的總和,並用給定的數字M確定除法後的餘數。獲勝者是首先決定正確結果的人。根據玩家的經驗,可以通過選擇更高的數字來增加難度。
你應該編寫一個程序來計算結果,並找出誰贏了這場比賽。
Input
輸入由Z賦值組成。它們的數目由出現在輸入的第一行上的單個正整數Z給出。然後分配如下。每個賦值都以包含一個整數M (1 <= M <= 45000)行開始。總數將除以這個數字。下一行包含玩家數H(1 <= H <= 45000)。接下來就是H行。在每一行上,正好有兩個數字Ai和Bi被空間隔開。兩個數不能同時等於零。
Output
對於每個組合,只有一條輸出線。在這條線上,有個數字,是表達的結果。
#include <iostream>
using namespace std;
typedef long long ll;
//x^n 快速冪方法
ll pow_mod(ll x,ll n, ll mod){
ll res=1;
while(n>0){
if(n&1) res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
int main(){
ll T;
cin>>T;
while(T>0){
T--;
ll M,H;
cin>>M;
cin>>H;
ll res=0;
for(int i=0;i<H;i++){
ll a,b;
cin>> a>>b;
res=(res+pow_mod(a, b, M))%M;
}
cout<<res<<endl;
}
return 0;
}