資訊學奧賽複賽複習16-CSP-J2022-01乘方-迴圈特判、pow函式、快速冪

new-code發表於2024-10-12
PDF文件公眾號回覆關鍵字:20241012
資訊學奧賽複賽複習16-CSP-J2022-01乘方-迴圈特判、pow函式、快速冪

此前解析題,P8813 [CSP-J 2022] 乘方,給出了迴圈的解題思路,當時在洛谷提交是透過的,後臺收到留言,a=1,b=1e9會炸吧?,確實啊整除要求1s內迴圈次數最大可以到10^7,現在測試資料明顯大很多,按測試資料有這個可能,沒想到CSP普及組第1題竟然翻車,去CCF官網去找測試資料,竟然沒有2022年的測試資料,去另外一個OJ上面測試了一下,竟然有超時測試用例

提交原碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e9;//允許的最大值 超出輸出-1 
int a,b;//輸入a b 
long long m=1;//儲存 a^b 
int main(){
	cin>>a>>b;//輸入a b
	for(int i=0;i<b;i++){//迴圈b次 
		m=m*a;//m從1開始每次乘以a 
		if(m>N){//如果大於允許的最大值 輸出-1 
			cout<<"-1";			
			return 0;//退出程式 
		}
	}
	cout<<m;//輸出 a^b 
	return 0;
}

分析

確實a=1的時候,b可以比較大,最後也需要迴圈結束才計算出結果,如果a不是1,迴圈次數就大大減少

可以分情況討論 a=1和a!=1

下面給出3種方法

1 迴圈特判

#include<bits/stdc++.h>
using namespace std;
const int N=1e9;//允許的最大值 超出輸出-1 
int a,b;//輸入a b 
long long m=1;//儲存 a^b 
int main(){
	cin>>a>>b;//輸入a b
	if(a==1){
		cout<<"1";
		return 0;
	} 
	for(int i=0;i<b;i++){//迴圈b次 
		m=m*a;//m從1開始每次乘以a 
		if(m>N){//如果大於允許的最大值 輸出-1 
			cout<<"-1";			
			return 0;//退出程式 
		}
	}
	cout<<m;//輸出 a^b 
	return 0;
}

2 用快速冪解法

如下用快速冪改造後的程式,不在超時,可以順利透過

#include <bits/stdc++.h>
using namespace std;
const int N=1e9;
long long a,b,ans=1;
long long quickpow(long long a, long long b) {
    while (b) {
        if (b & 1) {
            ans = ans * a;
        }
        if(a>N) return -1;
        if (ans > N) return -1;
        a *= a;
        b >>= 1;
    }
    return ans;
}

int main() {
    cin >> a >> b;
	cout << quickpow(a, b) << endl;	
    return 0;
}
/*
輸入 
1 992465817
輸出
1 
*/ 

普及組第1題用快速冪有點過分了,看看還有沒有其他解法

3 pow函式解法

#include<bits/stdc++.h>
using namespace std;
const int N=1e9;//允許的最大值 超出輸出-1 
int a,b;//輸入a b
double ans; 
int main(){
	cin>>a>>b;//輸入a b
	ans=pow(a,b);
	if(ans>N){
		cout<<-1<<endl;
	}else{
		cout<<(int)ans;//輸出 a^b	
	}
	return 0;
}
/*
輸入 
1 992465817
輸出 
1
*/ 

可以順利透過

這裡順便說一些pow函式

C++中有自帶的pow()函式,具有求指定底數的指定冪值。通常使用該函式求解冪

實現原理為快速冪,時間複雜度為O(logN)

#include<iostream>
#include<cmath>
using namespace std;
/*
  pow函式
  該函式接收兩個引數,base 為要取次方的數,exponent 為指數。返回結果為 base 的 exponent 次方 
  double x =pow(base,exponent);
  pow=(2,3)=8 
*/ 
int main(){
	int base=2;
	int exponent=3;
	double x=pow(base,exponent);
	cout<<x<<endl;
	exponent=4;
	x=pow(base,exponent);
	cout<<x<<endl;
	return 0;
}
/*
輸出
8
16 
*/ 

如下為原題

[題目描述]

小文同學剛剛接觸了資訊學競賽,有一天她遇到了這樣一個題:給定正整數 a 和 b,求 a^b 的值是多少。

a^b 即 b 個 a 相乘的值,例如 2^3 即為 3 個 2 相乘,結果為 2×2×2=8

“簡單!”小文心想,同時很快就寫出了一份程式,可是測試時卻出現了錯誤

小文很快意識到,她的程式裡的變數都是 int 型別的。在大多數機器上,int 型別能表示的最大數為 2^31−1,因此只要計算結果超過這個數,她的程式就會出現錯誤

由於小文剛剛學會程式設計,她擔心使用 int 計算會出現問題。因此她希望你在 ab 的值超過 10^9 時,輸出一個 -1 進行警示,否則就輸出正確的 a^b 的值

然而小文還是不知道怎麼實現這份程式,因此她想請你幫忙

[輸入格式]

輸入共一行,兩個正整數 a,b

[輸出格式]

輸出共一行,如果 a^b 的值不超過 10^9,則輸出 a^b 的值,否則輸出 -1

[輸入輸出樣例]

輸入 #1

10 9

輸出 #1

1000000000

輸入 #2

23333 66666

輸出 #2

-1

說明/提示

資料規模

對於 10% 的資料,保證 b=1。
對於 30%的資料,保證 b≤2。
對於 60% 的資料,保證 b≤30,a^b≤ 10^18。
對於 100% 的資料,保證 1≤a,b≤10^9。

相關文章