20190710B組

20190710B組

T1:100(100)

賽時:

怎麼現在比賽第一題都是數論?

這種一看就是規律題。

於是,我先將Fibonacci sequence打出來。

發現每15000個一個週期。

之後,分類討論一下就行了。

賽後:

對於80%的數據,根據遞推式用O(n)的方法就可以了。對於100%的數據,顯然要用到矩陣方法,這裏介紹兩種思路。

設F(n),S(n)分別爲Fibonacci sequence的第n項和前n項和,求第x~y項的和相當於求S(y)-S(x-1),於是問題變成了怎麼求S(y)和S(x-1)。

  1. 求出S(n)的通項,和F(n)的通項比較,可以發現S(n)=F(n+2)-1,於是就用矩陣乘法求出數列的第N+2項。但這樣的方法在比賽中不可取,因爲,,顯然除非你的手算能力足夠強,否則這需要浪費大量時間才能推倒出來。當然,由於S(n)=F(n+2)-1規律還是優美的,善於觀察的同寫幾項出來就可以發現規律.
  2. 根據F(n)=F(n-1)+F(n-2),S(n)=S(n-1)+F(n),我們可以按如下方法構造一個矩陣。

這種方法比較直觀,對矩陣乘法比較熟悉的同學應該很容易想到.

算法:

數論

T2:60(50)

賽時:

又事一道數論,可是就沒有前面幾題那麼簡單了。

經過一波亂推,一點效果都沒有。

最後只能打一個暴力。

感謝出題人,說好的50分,卻給了60分。

賽後:

對於50%的數據,直接枚舉答案判斷即可,對於80%的數據,用未優化的容斥原理可以解決,對於100%的數據,就要把一些冗餘的計算省去纔可以解決。

對於整數倍數的問題,一般很容易想到用容斥原理去做,對於這道題也是一樣的。由於題目答案不容易直接得出,而且答案又有明顯的有序性,於是我們可以二分答案,把原問題轉化成一個判定問題。

現在對於二分的答案ans,現在就是要求在[1,ans]這個範圍內,有多少個數滿足條件。對於這個問題,我們可以枚舉N個數當中的,設爲[1,ans]中有多少個數僅能被數整除,那麼[1,ans]中,滿足題目條件的答案是。如果,那麼ans就要加大,否則就減小。這樣的時間複雜度是,對於N=15這樣的數據顯然是難以在規定時間內出解,所以我們要進一步優化。

其實枚舉每一個,然後求出,在這個過程中有很多冗餘的計算。我們在對每個做容斥原理的時候可以發現,如果連同有k個數求出它們的交集,如果k是奇數,那麼答案就加上這個交集,如果是偶數,則答案減去這個交集。對於其餘的k-1個數,我們+-的都是同樣一個數,所以就沒必要枚舉所有的單獨求解。對於現在求出來的k個數的交集,如果k是奇數,那麼答案加上k*交集大小,如果k是偶數,那麼答案就減去k*交集大小,這樣的出來的結果是一樣的。時間複雜度就變成,這樣就可以在規定時間內出解了。

其實沒必要每次做容斥原理的時候都要去做GCD,GCD可以在開始的時候做一個預處理,f[state]表示狀態爲state(state是二進制化成10進制)的數的gcd是多少,這個預處理可以在2^n就可以做出來,然後做容斥原理的時候只就不需要重複做GCD了,時間複雜度變成,很完美地解決這個題目。所以,這樣與處理後即使不去掉冗餘計算的方法的時間複雜度變成,也可以在規定時間內出解。

算法:

數論

T3:50(50)

賽時:

終於出了一道字符串的題。

但是,太難了。

只好又打暴力。

幸好出題人有良心,暴力還有50分。

其實是一道狀壓dp題。

賽後:

對於50%的數據,枚舉k的全排列,然後生成新的字符串,然後按照題目要求做即可。對於100%的數據,要用到狀態壓縮Dp做。

首先可以發現,對於Len div k個塊,他們基本是互不影響的,只是在頭尾鏈接的時候有影響。而且在新的字符串中,每個塊裏面字母的排列順序都是一樣的,於是我們可以設S1[i][j]第i個字符和第j個字符不同個塊的總和,S2[i][j]表示相鄰兩個塊之間,前一個塊的第i個字符和後一個塊的第j個字符不相同的情況的總和。

於是我們就可以設f[i][j]當前排列以j結尾,在排列中的元素的狀態爲i(i是二進制轉化成的10進制)的壓縮後最小長度是多少。F[i][j]=min(f[i-(2^x)][x]+S1[k][j]);其中i and (2^x)<>0,且i and 2^j=0 於是我們就可以對於每個位置開頭,都做一次Dp,求出f[][],然後枚舉f[2^k-1][j],ans=min(f[2^k-1][j]+S2[start][j]),start就是當前枚舉的起始位置,初始狀態是f[2^start][start]=1;這個Dp的時間複雜度是O(*(Len/k)+)。

算法:

狀壓dp

T4:20(100)

賽時:

果然最後一題,比賽還是要出一道圖論。

圖論總離不開最短路和樹。

這題題目上說樹,其實一點關係都沒有。

直接最短路,並統計到這個點的最優解的方案數。

並用乘法原理,就AC了。

賽後:

給一個最多50個點的帶權無向聯通圖,無自環和重邊,現在要去掉圖上的一些邊,使得圖變成一棵樹,並且在結果的樹上,每個點到點0的距離等於在原圖中每個點到點0的最短距離。問可以生成多少個不同的樹。

個人比較喜歡這題,做之前需要好好思考一下。首先考慮離0點最近的那個點,一定和0點只連着一條邊,則這條邊是必選的;然後考察第二近的點,一種可能是和0點直接連的邊比較近,一種可能是經過剛纔最近的那個點再到0點的路比較近,不管是哪一種,選擇都是唯一的,而剩下第三種可能是兩者距離相同,這樣的話兩者選且只能選一個。以此類推,假設現在已經構造好了前k個點的一棵子樹,看剩餘點中到0點最近的點,這個點到0點有k種方法(分別是和那k個點連邊),其中有m個是可以保持最短距離的,則這一步可選的邊數就是m。一直構造,把方法數累乘,就能得到最後的結果。整個過程可以很好的符合dijkstra的過程,而生成樹的步驟和prim如出一轍。

算法:

最短路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章