効率的な表現のための刺激的な使用の少ないコード
問題の説明
プログラマーRostislavは、Splayツリーに基づいたLink / Cut Treeデータ構造に真剣に興味を持ちました。具体的には、彼は現在、露出手順を研究しています。
残念ながら、Rostislavはこの手順の定義を理解できないため、プログラマーSerezhaに支援を依頼することにしました。セレスハは、ロスティスラフが単純なタスクを解決するかどうかを支援することに同意しました(解決しない場合は、とにかくスプレイツリーが必要なのはなぜですか?)
整数l、r、kを指定すると、lからまでの範囲内のkのすべての累乗を出力する必要がありますrを含みます。しかし、Rostislavは、Agarという名前のネットワークゲームをGlebと一緒にプレイすることに興味があったため、これを行うことに時間を費やしたくありません。彼を助けて!
入力
入力の最初の行には、スペースで区切られた3つの整数l、r、およびkが含まれています(1≤l≤r≤1018、2≤k≤109)。
出力
昇順でlからrの範囲内にあるkのすべての累乗を出力します。そのような番号がない場合は、「-1」を印刷します(引用符なし)。
テーマ別分析
質問:l、r、kを入力し、区間[l、r]でkのすべての累乗を出力します。
例:入力1、10、2出力1 2 4 8
分析:指数関数について言うまでもなく、pow()、累積乗算、および高速指数関数はすべて許容されます。
しかし、解くプロセスでは、次のような長い長いバーストが発生します。kのn乗10^18
、k = 1000。この時点で計算を続けると、10^21
の数が表示されます。long longの値の範囲を超えると、unsigned long longでも格納できません。
解決策は、乗算が除算を変更することです。
など:数式if(pow(k, i) <= r )
を次のif(pow(k,i-1) <= r/k)
ように変更して、値をlong longの範囲内で取得できるようにします。
以下に2つのACコードを示します。コード1は高速べき乗法で、コード2は単純な方法です。
ファストパワーについてよく知らない場合は、手順に進んでください-> ファストパワーの基本的な考え方を説明してください
コード1(クイック電源方式)
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
ll quick_power(ll a, ll q) {
ll sum = 1;
while(q) {
if(q%2==1) sum *= a;
a*=a;
q /= 2;
}
return sum;
}
int main( ) {
ll l, r, k; cin>>l>>r>>k;
bool flag = true;
for(ll i = 0; quick_power(k, i)<=r ; i++) {
ll num = quick_power(k,i);
if(num>=l) {
cout <<(flag?"":" ")<< num;
flag = false;
}
if(num > r/k) break;
}
if(flag) cout << -1;
return 0; }
コード2(素朴なアプローチ)
#include<iostream>
#include<cmath>
using namespace std;
typedef unsigned long long llu;
int main( ) {
llu l, r, k; cin>>l>>r>>k;
llu t = 1, flag=0;
while(t <= r) {
if(t>=l) {
cout << t << ' '; flag = 1; }
if(t>r/k) break;
t*=k;
}
if(!flag) cout << -1;
return 0; }