Personal-Traning題解(一)

1.Codeforces Round #418 E (dp+組合數學):

https://loj.ac/problem/6094
http://codeforces.com/contest/814/problem/E
雖然題目是一樣的,但是時限不一樣,cf的時限大1s,所以在cf上這題O(n5) 可以過,但是loj就不行了,
codeforces:
把圖按照最短路分層,那麼這個圖需要滿足每個點都向上一層有且只有一條邊,並且沒有更向上的邊。
我們用dp[u][i][j][k][l] 表示前u 個節點,上一層有i 個讀數爲1 的插頭和 j 個度數爲2 的插頭,
這一層有 k 個度數爲 1 的插頭和 l 個度數爲 2 的插頭。注意我們甚至並不需要關心最短路到底是多少。
大力討論一下轉移就可以了。當前點先和上一層的一個點連接,剩下的度數可以留下,也可以和這一層的隨便連。

http://blog.csdn.net/sdfzyhx/article/details/73003862

loj:
O(n^3),參考一下cf上的KAN的做法。很神奇。
http://codeforces.com/blog/entry/52449.

2.二分圖染色。(組合數學,遞推公式)

https://loj.ac/problem/6160
這題是美團初賽的題,在一個完全二分圖上將邊進行染色的問題,紅色不共享端點,藍色不共享端點,綠色隨意染。

可以轉化爲棋盤模型,即 N×N 棋盤上放黑白棋子,每個格子至多放一個,同行同列沒有相同顏色的棋子。
bn 爲只有一種顏色,那麼,bn=ni=0CinAin
然後我們考慮容斥掉兩個顏色在同一格,如果一個格子既放黑又放白,那麼這一列和這一行不會有其他棋子,直接刪掉。

an=ni=0(1)iCinAin(bni)2

bn=2nbn1(n1)2bn2 ,可以花點時間想想左邊這個公式。
第一項是在第 n 行或者第 n 列上放一枚棋子或者不放的方案數,由於放兩枚棋子的情況會
被統計兩次,最後還需減去擺兩枚棋子的方案數,即第三項。

http://blog.csdn.net/u014609452/article/details/73744264

3.「美團 CodeM 初賽 Round A」倒水 (二分)

https://loj.ac/problem/6161

二分溫度,返回總共使用的體積。
這道題要注意一下精度。有的人用了long double,其實double也是可以的,分類二分溫度一下。
當全部t_i相同時,什麼操作都不需要,直接輸出。
當T>max{t_i},就for 200-300次二分,有可能升溫,也有可能降溫。
當T< min{t_i},就只能降溫了,直接算能不能把其他杯水是否能降到當前min{t_i},否則就Impossible。

4.「美團 CodeM 初賽 Round A」合併迴文子串 (區間dp)

注意:a,b子串中的字母是相對不變的。
考慮c中的迴文子串,既然是子串,就一定可以拆成 a, b 兩串的兩個子串的組合。
不妨 設是 a[i, j]與 b[k, l]的組合,則可以考慮動態規劃的狀態 dp[i][j][k][l] 表示
a[i, j]與 b[k, l]的組合能否組成迴文子串。 新組合的串的串頭一定是S1和S2串頭中的一個,
串尾一定是S1和S2串尾中的一個,則可以匹配第一個字符和最後一個字符來轉移,
根據第一個字符和最後一個字符分別來自 a 還是 b 共有四種轉移:
(注意分別l和1)(L和一)
dp[i][j][k][l]<dp[i+1][j1][k][l](i<j,a[i]=a[j])
dp[i][j][k][l]<dp[i+1][j][k][l1](i<=j,k<=l,a[i]=b[l])
dp[i][j][k][l]<dp[i][j1][k+1][l](i<=j,k<=l,b[k]=a[j])
dp[i][j][k][l]<dp[i][j][k+1]l1](k<l,b[k]=b[l])

5.「美團 CodeM 初賽 Round B」模(數學題。證明題。)

https://loj.ac/problem/6176

如果沒有進位,則數字和爲S(a)*n,一次進位對數字和的貢獻和是1-k,而數位和需要在模b下與c相等,
根據模方程的擴展歐幾里得解法,可以發現方程有解的必要條件是gcd(a,k1,b)|c 。然後我們要證明
這個條件是充分條件。
證明可以通過構造完成,對於任何a,一定【存在】其某個倍數p最低非零位的前一位不爲 9,
設此時最低非零位爲 t,則一定存在其倍數 q 使得最高位爲 k - t,設 q 在 k 進制下有 r 位,
考慮構造如下兩個數:

u=pkr+q
v=pk(r1)+q

可以發現u,v貢獻的a數量相同,而進位數恰好 v 比 u 多 1。
在模 b 意義下,構造xa+y(1k)
由於an可以任意大,我們在無限位中分散地擺放 x 個 a(可能有一些進位),再擺放一共
b 個 u 或 v ,其對 a 的數目沒有貢獻,但可以把進位數變成 [0,b-1]的任意值 即 y。
既然任意 xa+y(1k) 可以被構造出來,
所以在b剩餘系下有且僅有 gcd(a,k1,b)|c 的倍數可以被構造出來。

6.LOJ #6165. 一道水題(線性篩)

https://loj.ac/problem/6165

先用線性篩篩出[1,n]的所有素數,記爲p[i]。
答案是對每個p[i] ,求出最大的p[i]k ,滿足p[i]k<=n 。把所有這些p[i]k 乘起來就是答案。

注意:模是1e8+7。

7.「美團 CodeM 初賽 Round B」送外賣2 (狀壓dp)

https://loj.ac/problem/6177

三進制狀壓DP。dp[i][j] 表示三進制狀態爲 i,最終走到 j 點的最小時間花費。
那麼狀態對應一個位置是0表示沒有取餐,是1表示取了餐沒有送,2表示送到了,
然後分析每一位上是0還是1進行狀態轉移,轉移之前要預處理一下最短路,
這個點比較少直接Floyd預處理一下即可。

8.ACdream 1113 (概率dp)

http://acdream.info/problem?pid=1113

設dp[i]表示從i丟到n才達到目標和的期望的次數。
dp[n]肯定等於0,那麼就從最後往前推。

不難想到擲到123456的期望都是6.00。

dp[i] += dp[i+j]。
dp[i]+ = 6 ==> dp[i]/=(6 - tot) (tot表示當前擲到的數和之前擲到的書的和大於n的次數)

最終答案就是dp[0]。

9.ACdream 1124 喵喵的遺憾(Fib數模n的循環節)

http://acdream.info/problem?pid=1124

輸入 N 和 P ,輸出 Fib[Fib[Fib[n]]]%P

找循環節。
對於一個正整數n,我們求Fib數模n的循環節的長度的方法如下:
(1)把n素因子分解,即 n=pa11pa22pa33pakk

(2)分別計算Fib數模每個的循環節長度,假設長度分別是 x1,x2.....xk.

(3)那麼Fib模n的循環節長度L=lcm(x1,x2,.....,xk)

從上面三個步驟看來,貌似最困難的是第二步,那麼我們如何求Fib模pm 的循環節長度呢?

這裏有一個優美的定理:Fib數模 pm 的最小循環節長度等於G(p)p(m1) ,其中G(p)表示Fib數模素數p的最小循環節長度。
可以看出我們現在最重要的就是求G(p).

對於求G(p)我們利用如下定理:

如果5是模p的二次剩餘,那麼循環節的的長度是p-1的因子,否則,循環節的長度是2(p+1) 的因子。
順便說一句,對於小於等於5的素數,我們直接特殊判斷,loop(2)=3,loop(3)=8,loop(5)=20
那麼我們可以先求出所有的因子,然後用矩陣快速冪來一個一個判斷,這樣時間複雜度不會很大。

注意:需要注意的是P可能爲1,因此n==0或者1的時候,特判要輸出1%P而不是1.

10.HDU 2993 (斜率優化)

鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2993
題意i:給你一個長度爲 n 的序列,找出長度 >= k 的平均值最大的連續子序列。輸出其平均值。

題解:斜率優化+fread。數據後期加強了。不加fread不能過。
複雜度:O(n)。
斜率優化的例題。
先求出前綴和數組sum[],然後問題轉化成給出n+1個點求出兩點橫座標差>= k的點對所能構成的最大斜率。
然後樸素的想法是對於每一個可能的序列末端點 i,去尋找集合 [1,j](i-j+1 >= k)中與它能構成的最大斜率,不斷更新最大值。複雜度 O(n^2)。
然後斜率優化的思想,是對於不斷增長的集合[1,j] 維護一個下凸曲線,每次找出曲線中的切線即爲當前最優值。
找切線的時候,根據下凸曲線中切點斜率遞增的性質,可以刪除已經找到的切點之前的點。複雜度爲 O(n)。
數據被加強過,必須加fread才能AC。

11.HDU 1500(dp)

鏈接:
http://acm.hdu.edu.cn/showproblem.php?pid=1500

題解:
從大到小排序,保證k對筷子都有一支最大的條件 。
dp[i][j] 表示前 j 支筷子取 i 對筷子的最小 badness,不考慮第三根筷子 。
dp[i][j]=min(dp[i][j1],dp[i1][j2]+(L[j1]L[j])(L[j1]L[j])) ;(L爲筷子的長度)

12.HDU 1511(dp+思維)

鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1511

題解:
先從前往後dp,dp[i] 表示包括第i位往前,滿足題目要求能得到的最小長度。
這樣就可以求出,最後一個最小的滿足的數了。

求出最後一個最小的數後,從後往前dp,dp[i]表示從第i位開始往後,在滿足題目要求的情況下,能得到的最大長度。
這樣就可以求出,按順序依次最大的。

簡而言之:
①從前往後DP,找出最後一個數的最小值,即最後一個數儘可能的小;
②從後往前DP,找出最前面一個數的最大值,即第一個數儘可能的大。

14.Codeforces Alpha Round #21 D(狀壓dp)

鏈接:http://codeforces.com/contest/21/problem/D

題意:給一個無向圖,要求從1出發回到1,但是必須經過圖中每一條邊,並且至少經過一次。注意:這不是歐拉回路。

/*********************************************************************/
判斷歐拉路是否存在的方法:
有向圖:圖連通,有一個頂點出度大入度1,有一個頂點入度大出度1,其餘都是出度=入度。
無向圖:圖連通,只有兩個頂點是奇數度,其餘都是偶數度的。

判斷歐拉回路是否存在的方法:
有向圖:圖連通,所有的頂點出度=入度。
無向圖:圖連通,所有頂點都是偶數度。
/*********************************************************************/

題解:狀壓DP。
度數爲偶數的點不需要被考慮,只需要考慮度數爲奇數的情況。首先每條邊必須要訪問一次,所以,所有邊權加起來就是答案的初值。 
然後度數爲奇數的點就需要訪問之前已經走過的邊。我們考慮兩個度數爲奇數的點可以組合一下,就變成了度數爲偶數的點,
相當於是在這兩個點之間新連了一條邊,我們可以floyd預處理一下兩點之間的最短路。
然後狀壓dp,狀態表示當前哪些結點的度數爲奇數,然後枚舉每次連哪兩條邊就可以了。

now = i^(1<<(j-1))^(1<<(k-1));
dp[now] = min(dp[now],dp[i]+ w[j][k]);//取或不取 j 和 k 兩條邊

15.Codeforces Beta Round #14 (Div.2) D (樹形dp)

鏈接:http://codeforces.com/contest/14/problem/D

題意:
給定一個無向圖,含有一定的路。從中找出兩個最長的路徑(每條路徑有一些相通路組成)。
這兩個路徑不能經過公共的點,求什麼時候兩條路徑的乘積最大。

題解:
把一個圖沿一條邊割開,分成兩個樹,求這兩個數中最長的路的乘積。
這裏需要分別求兩個樹的直徑。
因爲題目數據不大,直接枚舉邊即可。(n^2)
DFS從當前點開始搜索,把枚舉的那條邊先當作刪掉,DFS當前點存在的最大深度和次大深度。
兩個相加不斷更新最值,便可得到其中一邊樹的直徑。
同樣再DFS一次就可以得到另外一邊樹的直徑。
最後相乘即可。

複雜度就是:O(n2) .

16.Codeforces Beta Round #14 (Div.2) E (dp)

鏈接: http://codeforces.com/contest/14/problem/E

題意:
畫駱駝峯,給你n步,要你求可以畫t個駱駝峯的方案數。
要求駱駝峯的高度不能超過4。
(3≤n≤20, 1≤t≤10).

題解:
四維dp。
dp[n][t][j][s]
n代表點數(步長),t代表尖峯數,j代表高度,s代表上升(1)還是下降(0)的方案數。
初始化第一步,第一個尖峯,高度爲j的是一個上升峯。
因爲初始值看成了一個上升峯,那麼步數爲2時會出現下降峯。比如21,32這些。但是這些不合法。
所以要把步數爲2時的置0就可以了。
轉移方程:

一.更新上升峯(1:上升峯再加一個上升,2:下降峯加一個上升)
dp[n][t][i][1]+=(dp[n1][t][j][1]+dp[n1][t1][j][0]);

二.更新下降峯(1:下降峯再加一個下降,2:上升峯加一個上升)
dp[n][t][i][0]+=(dp[n1][t][j][0]+dp[n1][t][j][1]);

複雜度:O(n3) .

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