你們好,原本今天想寫一篇算法和數據結構的。可是看了一眼計劃,發現基本上大部分基礎的內容都已經講過了。接下去就是一些競賽相關的算法了,恰好最近是校招季,因此寫一點筆試題的題解,也許對你們的招聘有點用。node
這一次選了拼多多的校招筆試題其中的一題,在寫文章的時候還看到了小馬智行的。也就是那個樓教主創辦的著名的pony.ai,可是我點進去看了一眼,發現大部分都是acm競賽題的風格,難度對於普通學生而言有些高了。因此沒有采納,改選了拼多多的試題。ios
給定一個整數N,表明N個盒子。第i個盒子當中有i個球。web
咱們能夠選定一個N之內的天然數X,多多雞會把全部盒中小球數量大於X的盒子減小X個球。如今想要用最少的步驟將全部盒子的球清空,請問最少須要多少次操做?算法
第一行輸入一個整數t,表示測試組數。數組
對於每一行都輸入一個整數N( )數據結構
要求對於每組數據輸出一個整數做爲結果。編輯器
咱們仔細分析一下,會發現這題的難點有兩個。第一個是這個N的範圍太大了,對咱們的複雜度限制得很高。第二點是盒子當中球的數量是動態的,在如此苛刻的複雜度要求下,咱們很難掌握全部盒子的動態。svg
但若是你有足夠多經驗的話,會發現N的範圍其實並非限制而是提示。N的範圍達到1e9,在這個量級下咱們連 的計算都是會超時的,也就是說全部須要遍歷盒子的算法均可以放棄了,看似苛刻,其實會節省咱們不少時間。若是N的範圍給個1e6,那纔是真的噁心。估計不少同窗要被騙了,苦苦思考怎麼樣經過模擬的方法來計算。函數
既然範圍是1e9,那麼沒的說,這題必定是經過一些巧妙的方法來計算的。可是到底是什麼巧妙的方法,咱們幹想是想不出來的,要想知道也不難,嘗試着去作一下就能夠找到門道了。測試
咱們假設咱們第一次選擇了k,也就是序號大於等於k的盒子裏球的數量都減小了k。那麼減小以後的狀況變成什麼樣了呢?咱們列出來看看: 。
有些同窗看到這個可能會想第二個數字選什麼,若是你這麼想了,可能你作的題目還不夠多,不夠敏感。其實看到這個已經能夠發現,當咱們選擇了k以後,數組被拆分紅了兩個部分,左邊是0到k-1,右邊是1到N-k,中間0是分割線。
這一點發現有什麼用呢?其實頗有用,咱們首先來作一個假設,假設k-1 > N-k,也就是左邊部分的元素比右邊更多。那麼無論咱們接下來如何操做,其實只要咱們的操做可以消除掉左邊的部分,右邊的天然也會跟着消除。同理,若是k-1 < N-k,也是同樣的。因此咱們經過選擇了k以後,數組拆分紅了兩個部分,答案只和其中的一個部分有關,而且是和其中元素最多的部分有關。
那麼根據這一點,咱們能夠直接寫出表達式來表示N時的答案:
這個式子看起來很複雜不知道如何解,但其實也很簡單,咱們還有一個條件沒有用上。就是f必然是一個遞增函數,這個其實不須要嚴格證實,咱們直觀上就能夠感覺出來。既然f是遞增函數,那麼上面式子當中不少元素的大小關係就都明顯了。
這樣遞推式就出來了,咱們接下來要作的就是根據這個遞推式寫出它的通項。
咱們把上面的式子所有累加在一塊兒,右邊帶有f的項會被所有消掉,最終獲得: 。這個表達式有了,那麼代碼天然手到擒來。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include "time.h"
#include <functional>
#define rep(i,a,b) for (int i=a;i<b;i++)
#define Rep(i,a,b) for (int i=a;i>=b;i--)
#define foreach(e,x) for (__typeof(x.begin()) e=x.begin();e!=x.end();e++)
#define mid ((l+r)>>1)
#define lson (k<<1)
#define rson (k<<1|1)
#define MEM(a,x) memset(a,x,sizeof a)
#define L ch[r][0]
#define R ch[r][1]
using namespace std;
const int N=1000050;
const long long Mod=1000000007;
int t, x;
int main() {
scanf("%d", &t);
rep(z, 0, t) {
scanf("%d", &x);
printf("%d\n", int(log(x)/log(2)) + 1);
}
return 0;
}
這道題從難度上來說其實不大,可是真正在筆試的過程中遇到,估計不少同窗可能作不出來。倒不是由於算法有多難,而是會一開始的時候就走了歪路,好比去思考怎麼樣選擇k,好比去想遞推的解法等等。這種對問題的敏感和思路是須要練習的,並非看幾篇文章或者是聽聽大牛講課就能夠得到的。
通常公司的筆試題不會很難,每每都是這種須要縝密思考的思惟題,這種題多作多練很容易就摸到套路了。若是對這些問題感興趣能夠看看codeforces專題,裏面有不少有趣的思惟題。
今天的文章就到這裏,衷心祝願你們天天都有所收穫。若是還喜歡今天的內容的話,請來一個三連支持吧~(點贊、關注、轉發)
{{uploading-image-72342.png(uploading...)}}