CSP S2019部分題解

2022-02-12 13:52:16 字數 2383 閱讀 5044

這其實是某年的一道初賽題,但筆者刷初賽的時候嫌太麻煩了沒去看.

然鵝它考了,這倒無所謂, \(d1t1\) 難度還是做得出來的.

通過觀察構造方法,我們可以發現,乙個有若干位的格雷碼一定是從最高層起每一層都去掉乙個高位,最後得到空串.

我們還可以發現,乙個格雷碼在某一層應該去掉的高位是 \(0\) 還是 \(1\) 只與它位於該層的前半段還是後半段有關.

於是,我們得到了乙個遞迴的構造方法.

即從最高層開始,判斷當前碼在前半段還是後半段,然後層數減一,對應地去修改下一層時的編碼編號.

需要注意到這樣實現的乙個重要依據是,每一層都是由上一層加字首 \(0\) 正向排列和加字首 \(1\) 反向排列拼接而成.

還有一點細節需要注意 \(:\) 本題的資料範圍極大,必須使用 \(unsigned \: long\: long\) 才能存下,且不能為了方便把編號向右平移.

總複雜度 \(:\theta(log_2)\) 其中, \(n\) 是格雷碼的位數.

其實並不是很難的一道題,但因為我太菜了,所以考場上確實沒做出來.

注意到,題目要求我們對於樹上的每乙個點求出它到根的路徑上合法的括號子串行的個數的異或和.

顯然的一點是乙個點的答案一定是繼承父親的答案並加上自己貢獻.那麼現在的問題就是如何去計算貢獻.

對於乙個點 \(v\) , 其父親記為 \(u\) , 某個點 \(x\) 的貢獻記為 \(con_x\) 則有 \(con_v=con_u+1\) .

這是可以通過觀察得到的.貢獻的問題也已經解決掉了.

這時候我們發現,乙個點的括號能產生貢獻,當且僅當它與以它為終點的一段字尾能匹配成乙個合法的括號序列.

於是我們就有遇到了乙個新問題 \(:\) 如何在 \(dfs\) 過程中維護乙個歷史版本的棧 \(?\)

主席樹維護顯然可行,但沒有必要,而且會產生大量的空間開銷,雖然開得下,但主席樹對很多人來說也頗不友好.

我們可以發現,在某乙個點向下 \(dfs\) 時至多會有乙個括號被壓入棧中,也至多會有乙個括號被彈出.

那麼對於某一點,我們就記錄在該點處棧是否發生變化,是彈出還是壓棧,並記錄彈出/壓棧的元素的是誰,回溯時復原即可.

總複雜度 \(:\theta(n)\) , 相當優秀.

放在 \(d2t1\) 的位置上,頗具難度,但也無話可說.

我們把每一種烹飪方法看作乙個二維矩陣的行,每一種主要食材看作乙個二維矩陣的列.

首先考慮題目中的三個限制.第乙個限制沒什麼好說的,就是方案非空.

第二個限制實際上告訴了我們做菜的上界是 \(n\) 個.即每行中至多選擇乙個.

第三個限制是本題中最為棘手的乙個,也是卡死了很多人的乙個限制,如果沒有這個限制,說的不客氣點,\(sb\) 題.

第三個限制其實是說在乙個合法的方案中每一列至多選 \(\left\lfloor\frac\right\rfloor\) 個,其中 \(k\) 是該方案的菜品總數.

容易發現,第三個限制中不合法的列,在乙個方案中至多只有一列,於是我們可以考慮去容斥.

因為滿足前兩個限制的方案數非常容易計算,而指定某一列不合法的方案數也不難計算.

於是考慮設 \(f_\) 表示對於列舉的當前列 \(cur\) ,前 \(i\) 行中當前列選了 \(j\) 個其他列選了 \(k\) 個方案數.

\[f_=f_+f_\times v_+f_\times ( s_i - v_)

\]其中, \(v_\) 表示第 \(i\) 種烹飪方法,第 \(cur\) 種主要食材能做多少菜,\(s_i\) 表示第 \(i\) 行的和.

所有不合法的方案就是\(:\)

對於列舉的每一列的 $$\sum_}$$ 求和.

總方案數可以設 \(g_\) 表示前 \(i\) 行中選了 \(j\) 個的方案數.

\[g_=g_+g_\times s_i

\]於是總方案數就是 \(:\)

\[\sum_^}

\]這樣的總複雜度是 \(\theta(mn^3)\) 的,能夠通過過半的測試點.

這時候考慮優化上面的做法.對於總方案的求法已經夠優秀了,所以不需要再額外優化.

只需要考慮如何優化不合法方案的複雜度即可.

我們發現,在轉移的時候,我們實際是不關心當前列選的具體個數和其他列選的個數的,我們只需要知道當前列的個數減去其他列的個數的差就能知道某個方案是否是合法/不合法的.

於是考慮差值 \(dp\) ,狀態變為 \(f_\) 表示前 \(i\) 行,當前列減其他列的差為 \(j\) 的方案數.

\[f_=f_+f_ \times v_ + f_\times ( s_i - v_ )

\]這是最樸素的方程,然而實際的方程卻不是這個樣子.

因為轉化為差值之後就不可避免地會出現負值,而陣列下標不允許負值的出現,這時我們可以選擇把下標整體右移 \(n\) ,這樣就能保證不出現負下標了.

總複雜度為\(:\theta(mn^2)\),足以通過本題.

CSP S 2019模擬 題解

傳送門 很顯然的考慮把每個質因子給壓到dpd p裡但是有很多指數為0 1 0 1的質因子的情況 考慮f i f i 為強制選i i的情況 那麼s i f i s i 1 s i f i 1 s i f i s i 1 s i f i 1 這樣記字首和更新就可以了 這樣只需要壓6 6個質因子就可以了 ...

題解 CSP S2019初賽 取石子

取石子 alice和bob兩個人在玩取石子遊戲。他們制定了nn條取石子的規則,第ii條規則為 如果剩餘石子的個數大於等於a i a i 且大於等於b ilb il,那麼他們可以取走b i b i 個石子。他們輪流取石子。如果輪到某個人取石子,而他無法按照任何規則取走石子,那麼他就輸了。一開始石子有m...

CSP S 2019 遊記 完結

day 12 to day 5 不知道哪根筋不對了,臨近csp,考試居然天天寫掛暴力,心態一天比一天 於是為了練碼力 退役前留個紀念,開始寫各種大模擬和資料結構 豬國殺寫了三天,總耗時6h 線段樹的資料結構題寫了四天,總耗時9h splay的資料結構題 不好意思我太懶了 csp應該不會考平衡樹所以不...