1. 程式人生 > >P5035金坷垃題解(快速冪的講解)

P5035金坷垃題解(快速冪的講解)

 

首先經過讀題,我們發現找到合格的金坷垃,怎麼樣的金坷垃才是合格的呢?(我們不難發現1肯定是合格的【題目已經給出了】)

然後我們開始手推一下之後合格的金坷垃:

2-1=1(合格)

3-1-1=1(不合格(1重複減了))

4-2-1=1(合格)

......


對於任意一個數,他減去他的任意一個約數(除它本身)最小值都為他本身的1/2,我們可以考慮倒著推回去這樣就行了,發現合格的金坷垃必須是2的倍數,我們可以用反證法來證明,如果一個合格的金坷垃不是二的倍數,那麼最後經過前面的相減肯定會變成一個質數。

一個質數的約數(除它本身)只有1,但我們用一個數只能用一次,那麼這個金坷垃就不是一個合格的金坷垃

如90:

90-45=45;

45-15=30;

30-10=20;

20-5=15;

15-3=12;

12-6=6;

6-3=3;

最後剩下了3(質數)【這個各位可以自己推一下】


1;

1+1=2;

1+1+2=4;

1+1+2+4=8;

1+1+2+4+8=16;

......

不難發現第i個合格的金坷垃就是2的i-1次方,這樣我們就可以用快速冪來解決了


直接用快速冪模板就能過了!

#include<bits/stdc++.h>//萬能頭
using namespace std;
const int mod=123456789;//要mod的值
long long n;
long long qmi(long long x,long long k){//快速冪模板
    long long res=1;
    while(k>0){
        if(k&1){
            res=res*x%mod;
        }
        x=x*x%mod;
        k>>=1;
    }
    return res;
}
int main(){
    cin>>n;
    cout<<(qmi(2,n-1)%mod+mod)%mod<<endl;//輸出2的n-1次方,(qmi(2,n-1)%mod+mod)%mod是防負數的,但這個沒有負數就可以不用寫
    return 0;//結束程式
}

根據這個題目我們可以引出快速冪了:

顧名思義,快速冪就是快速算底數的n次冪。其時間複雜度為 O(log₂N), 與樸素的O(N)相比效率有了極大的提高。這就可以讓我們不用擔心t掉了。

快速冪演算法的核心思想就是每一步都把指數分成兩半,而相應的底數做平方運算。這樣不僅能把非常大的指數給不斷變小,所需要執行的迴圈次數也變小,而最後表示的結果卻一直不會變。(一般在題目當中都會mod一個數字,我們也不用考慮寫高精度) 讓我們先來看一個簡單的例子: 我們用ans來記錄答案 因為這個是乘法,所以說ans賦值為1; 3^10=3*3*3*3*3*3*3*3*3*3*ans 3^10=(3*3)*(3*3)*(3*3)*(3*3)*(3*3)*ans 3^10=(3*3)^5*ans; 3^10=9^5 -----------------  一次操作(n為偶數的情況)(n為偶數的情況,ans的值不會改變) 3^10=(9^4)* 9 ans=ans*9; 3^10=  (9^4)*ans 9^5= (81^2)*ans -----------------  又一次操作(n為奇數的情況)(n為奇數的情況,ans的值等於它本身×底數)   所以在實現程式碼之前,我們先在這裡總結一下快速冪
  • 優勢:
  • 時間複雜度為 O(log₂N), 與樸素的O(N)相比效率有了極大的提高
  • 用法:
  • 指數為奇數,ans=ans*底數,底數平方,指數右移一位(除以2向下取整)
  • 指數為偶數,ans不變,底數平方,指數右移一位(除以2)
 程式碼實現
int qmi(int m, int k, int p)
{
    int ans = 1 % p, t = m;
    while (k)
    {
        if (k&1) ans = ans * t % p;//如果指數是奇數的話,ans=ans*底數t
        t = t * t % p;//底數平方(無論指數是奇數還是偶數都要平方)
        k >>= 1;//指數右移一位(除以2或者向下取整) 
  }
  return res;
}