1. 程式人生 > >2017.07.11【NOIP提高組】模擬賽B組

2017.07.11【NOIP提高組】模擬賽B組

span 結果 數組 運算 重要 eight 一點 對數 理解

Summary

  今天的比賽打得還不錯,第一題被同桌灌輸的貪心,純模擬洗腦了,然後steal的看了一下,發現怎麽也對不了,一直在檢查。最後10分鐘才找出反例,推出動態規劃方程,沒有想到怎麽轉移,比賽就結束了。第二題題意理解錯誤了,但是還是拿到了充滿希望的10分,第三題看到題目就直接上了線段樹,我想沒幾個人能像我一樣5分鐘想完並打完這道題了。貪心一定要看到反例,不能盲目去做,否則浪費了時間,更讓心情愈來愈不甘。

Problem

T1 解題

題目大意

  奶牛有P (P≤300) 道題目要做。他們的月薪是M (m≤1000) 元。
  每做一道題需要兩筆付款,第一筆A_i(1≤A_i≤M)元在做題的那一個月初支付,第二筆B_i元(1≤B_i≤M)在做完後的下一個月初支付,牛沒有任何存款意識

  題目必須按大概順序解出。比如,題目3必須在解題目4之前或同一個月解出.

  找出牛們做完所有題目並支付完所有款項的最短月數。

想法

  剛開始比賽的是被被傳銷洗腦成貪心,結果一直在檢查錯誤,殊不知,其實是動態規劃,下面給一個貪心的反例

  7 3
  2 5
  2 5
  5 2

  按照貪心,答案是6,其實最優應該是5

  我們有兩種DP的方法,一種是被姚大神稱為垃圾的,另一種也是被他稱為垃圾的

(1)

  我們設f[i,j]表示你解答前i個問題,最後一次連續解答了j個問題的最少月份數

  狀態轉移方程:

  1.在前i~j件事情付清尾款當月付j個項目的首款:d[i][j]=min(d[i-j][x]+1) 當sumb[j-1-x+1][j-1]+suma[j][i]≤pay}

  2.在前i~j件事情付清尾款後的一個月付j個項目的首款:d[i][j]=min(d[i-j][x]+2) 當 sumb[j-1-x+1][j-1]≤pay && suma[j][i]≤pay

  x表示上一個月同時付了x個problem的首款,suma,sumb分別是輸入的前綴和

  假設我們現在已經完成了i-j個problem的解答(上一個月同時付了x個problem的首款),現在要付連續j個problem的首款。在本月結束時,我們要保證前i個程序都已經在解答中(或者已經解出)且本月進行了j個解答,那麽截止本月初付過前x個problem的尾款後,總共是完成了i-j個problem;本月要完成的問題的編號是從i-j+1

一直到i,那麽我們就可以推出,上一個月要完成的問題的編號為i-j-x+1i-j。按照我們上面分析的,我們有兩種選擇:
  1.同時付清上一組x個problem的尾款和這一組j個problem的首付;
  2.在上一組x個problem的尾款付清後,進行j個problem的首付。
設suma[i][j]、sumb[i][j]分別為首付前綴和尾款前綴和,分別表示第i個問題至第j個問題的首付之和、第i個問題至第j個問題的尾款之和。
  無論如何,都需要保證這個月的結余必須為正數、且下一個月將要付清的本月尾款必須也不能超過工薪(如果大於了工薪,那麽本月或下一個月奶牛就破產了=_+)。

(2)

  我們設f[i,j]表示你在第i天,選了j個任務的最少欠費。枚舉一個k,表示上個月選到最後的題目是多少

  方程為f[k,i]:=min(sum_b[j+1,i])當sum_a[j+1,i]+f[k-1,j]≤m

  sum_a[j,i]表示a[j]到a[i]的和,sum_b亦然

  sum_a[j+1,i]+f[k-1,j]≤m其實就是如果上個月選的題目的首付,之前的欠費,是否會使奶牛破產

  f[k,i]表示,當前的欠費,上一次選了多少題目的第二筆付款,欠費就是對應的sum_b

T2 JIH的玩偶(tree)

題目大意

  這張網以玩具廠為總代理(根),構成一顆樹。每個節點都代表一個客戶,且每個節點都有重要度ai。JIH想將這些客戶劃成若幹類別,當然同一類的客戶重要度相差太大總是不妥。所以JIH決定先進行市場調研。JIH會選擇兩個客戶X,從X向根走一共k個節點進行調查。調查的結果是這條路徑上重要程度相差最大的兩個客戶的差值是多少。因為特殊需要,要求重要度大的客戶必須在重要度小的客戶後面(順序為X到根,若序列為遞減,則輸出0,詳情見樣例)。

想法

  樹上倍增,第一次做

  其實就是類似於樹上求RMQ,跟RMQ思想差不多,維護類似的,設f/gmax/gmin/gans[i,k]表示從i到i的第2k個祖先中,對應的編號,最大值,最小值,最大值減最小值。

  其實就是在是查詢難一點而已

  對於每個詢問,先找到最大的k使得g[x,k]在終點或終點以下,

  Ans=max(ans,gu[x,k],gb[x,k]-last);

  last:=min(last,gs[x,k]);//最小值

  x:=g[x,k];//當前點

  如此遞歸求解,直到x為終點

  畫一下圖就知道了,其實很簡單的,不必多說

T3 進化序列(evolve)

題目大意

  一個基因Ax 可以進化為序列中在它之後的基因Ay。這個進化的復雜度,等於Ax | Ax+1...| Ay的值,其中| 是二進制或運算。
  Abathur 認為復雜度小於M 的進化的被認為是溫和的。它希望計算出溫和的進化的對數。

想法

  維護一個最大的k,表示當前a[i~k]的數or起來是符合題目條件的,且保證k>i

  其貢獻值為k-i

  因為or運算是不會變小的,所以k是線性的,關鍵是快速判斷a[i~k]的數是否符合題目條件

  可以用線段樹,樹狀數組,RMQ

  不會的可以去學。

2017.07.11【NOIP提高組】模擬賽B組