昨天刷計蒜客,遇到這樣一道題:
等差數列
我把題目搬過來:
乙個等差數列是乙個能表示成 a,a+b,a+2b,...,a+nb(n=0,1,2,3,...)a,
a+b,
a+2b
,...
,a+n
b(n=
0,1,
2,3,
...)
的數列。
在這個問題中 a
a 是乙個非負的整數,b
b 是正整數。寫乙個程式來找出在雙平方數集合(雙平方數集合是所有能表示成 p2+q2p2
+q2 的數的集合) s
s 中長度為 n
n 的等差數列。
輸入包括兩行,第一行為 n(3≤n≤25)n(
3≤n≤
25) 要找的等差數列的長度。第二行是找到的雙平方數 p
p 和 q
q 的上界 m(0≤p,q≤m)m(
0≤p,
q≤m)
。輸出一行或者多行,如果沒有找到數列,輸出none
。否則輸出乙個整數對a b
(這些行應該先按 b
b 排序再按 a
a 排序)
題目讀完,我的第一反應就是深搜,因為它本質上還是在所有可能性大組合中搜尋符合條件的佇列。
於是風風火火就寫起來了:
//// main.cpp
// ari_prgr
//// created by horizon42 on 2018/3/20.
//#include #include #include #include #include #include using namespace std;
// 構造乙個結構體儲存a,b, 並過載它的 < 比較符號,以方便排序。
struct a_b
for (int i =cur+1; i<=maxn; ++i)
}int main()
}for(auto i = tmp.begin(); i!=tmp.end(); ++i)
cout《結果呢? 結果當然是超時了!!!
而且這已經是我絞盡腦汁減少遞迴次數提高效率的結果。折騰半天也就從通過一組編成了通過二組……
沒想到,正解竟然那麼暴力。
先看**:(**是我了解解題思想之後自己寫的)
//// main.cpp
// ari_prgr_check 逆向思維的應用
//// created by horizon42 on 2018/3/21.
//#include using namespace std;
bool checked[125001] = ; //標記某個數字是不是符合條件的平方數
int a[125001] = ; //儲存所有可能的a,也就是所有平方數
int main(int argc, const char * argv)
}//初始化a
for (int i=0,j=0; i<=m*m*2; ++i)
}bool none = true;//標記是否沒有結果
int b=1;
int max_b = (m*m*2)/(n-1);
//b也就是公差由小到大開始遍歷,有排序效果
for (; b<=max_b; ++b) {
//為當前的b公差搜尋可能的a
for (int i=0; a[i]+(n-1)*b<=m*m*2; ++i) { // a[i]<=m*m*2這種寫法 依然浪費了時間
//判斷是不是等差數列
bool is_checked = true;
for (int n=1; n**注釋得很清晰了,核心思想就是直接暴力搜尋所有符合條件的組合。但它之所以效率高,主要有3點:
使用乙個標記陣列,避免出現重複的平方數的同時,也方便在搜尋時判斷等差數列成不成立
判斷是否為等差數列時,用逆向思維,如果a[i]+n*b並沒有在標記陣列中被記錄,則說明這個組合不符合要求。
從b也就是公差的角度開始搜尋,節省了排序的時間。
可以說,受益良多。
賭神(逆向思維)
時間限制 c c 1秒,其他語言2秒 空間限制 c c 32768k,其他語言65536k 64bit io format lld 買定離手,買定離手!到底誰能捧盃本次新生賽?億電競的投資人 億大佬 向你介紹遊戲規則 你可以參與數次競猜,每次競猜都有兩個待選隊伍a和b 當然不是競猜新生賽的隊員哈 你...
逆向思維(域外箴言)
因閉口不言而讓別人以為你是傻瓜,比因為張嘴說話而證實別人的猜想,要明智得多。事先如果沒有充分的準備,我無法做好即興演講。一定要聽父母的話 當他們在場的時候。防止受 的好辦法很多,其中最保險的方法是做個膽小怕事的人。行善是偉大的 勸人行善更偉大,而且做起來也更容易。我從不讓學校生活干擾我學習真正的知識...
Flower 規律 逆向思維)
flower 傳送門 題解 逆向思維 規律 因為每次剪n 1,所以逆向就是控制n 1朵不變,每次增高1朵,直到所有等高,即所有的高度都等於最高的那一朵,記錄增高的次數為sum,反過來就是最高的那個減少sum,如果減少sum後小於1則不成立,大於等於1,則需要減少sum次。sum 每朵花與最高的差的和...