其實省選在四天前就已經結束了,但因爲題目難度略大我到今天上午才補完全部題目……(捂臉逃)考場上很幸運,打完了全部我會寫的部分分,最後Round1的110分 + Round2的70分,勉強算是沒有被聯賽day2的文件夾坑太多。。。
git
目前網上比較容易找到的題解彷佛只有ydc教主的這份:http://ydc.blog.uoj.ac/blog/336,不過對於我這種水平的人來講這份題解還不是很好理解,那麼我再來稍微補充一點更基礎的內容吧。。
算法
有一棵點數爲N的樹,樹邊有邊權。給你一個在0~N以內的正整數K,你要在這棵樹中選擇K個點,將其染成黑色,並將其餘的N-K個點染成白色。將全部點染色後,你會得到黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。 數組
其中$1 \leq N \leq 2000, 0 \leq K \leq N$。
ide
從點和點的距離入手不太好分析……我在考場上想了一兩個小時最後仍是棄療了,連暴力都沒心情寫,交了一份靠運氣的貪心騙分。
函數
其實呢……因爲樹上每一條邊都是橋,咱們能夠從每一條邊兩端的黑白點數入手,也就是考慮每條邊對答案形成的貢獻。定義函數f(v, i)表示在v子樹中,共將i個點染色後,能獲得的「子樹中全部點的父邊的對答案的貢獻之和」的最大值。這樣每棵子樹就成了一個可分割的子結構,就能夠作樹形揹包了。
spa
根據官方題解中給出的那種神奇的證實,這樣作的時間複雜度是$O(N^2)$.指針
有一棵點數爲N的樹,以點1爲根,且樹點有邊權。而後有M個操做,分爲三種: code
操做1 1 x a:把某個節點x的點權增長a。 blog
操做2 2 x a:把某個節點x爲根的子樹中全部點的點權都增長a。 遊戲
操做3 3 x:詢問某個節點x到根的路徑中全部點的點權和。
對於100%的數據,N,M<=100000,且全部輸入數據的絕對值都不會超過10^6
其實咱們這樣來看……對於一次操做(2 u x),咱們來考慮此次操做對u的某個後代v的貢獻。不難看出,從u到v路徑上的每一個點的權值都被增長了x,這個操做對v的答案的增量$d_v = (dist(u, v) + 1) * x$ 。然而dist(u, v)這個東西彷佛不太容易做爲區間修改的增量。因爲u是v的祖先,咱們不妨把dist拆一下,那麼$d_v = (dep_v - dep_u + 1) * x$,或者$d_v = dep_v * x - (dep_u - 1) * x$.(其中$dep_i$表示i點到根的距離)這時咱們其實已經把此次操做的貢獻拆成了一個關於點v的深度的一次函數,那麼每次進行操做時只要分別修改兩項的係數就能夠了。
有一個長度爲N的數組,甲乙兩人在上面進行這樣一個遊戲:
首先,數組上有一些格子是白的,有一些是黑的。而後兩人輪流進行操做。每次操做選擇一個白色的格子,假設它的下標爲x。接着,選擇一個大小在1~n/x之間的整數k,而後將下標爲x、2x、...、kx的格子都進行顏色翻轉。不能操做的人輸。
如今甲(先手)有一些詢問。每次他會給你一個數組的初始狀態,你要求出對於這種初始狀態他是否有必勝策略。假設兩人總能作出最優決策。
對於30%的數據,N<=20;
對於50%的數據,N<=1000000;
對於70%的數據,N<=10000000;
對於100%的數據,N<=1000000000,K,W<=100,不會有格子在同一次詢問中屢次出現。
好難啊……TAT考場上果斷30分暴搜……
出題人kzf告訴咱們,能夠修改一下游戲的定義:每一步能夠選擇黑格子或白格子,最終能將全部格子都翻成黑色的人贏。因爲每次翻轉黑格子的操做都不可能直接帶來勝利,而任何一步選取黑格子進行的有利操做都能由對方經過再翻一次這個格子抵消掉,根據假設「兩我的都是足夠聰明的」,咱們知道遊戲中必定不會有人選擇黑格子。這就保證了這種轉換的正確性。
所以咱們能夠把每一個黑色的位置都當作偶數個白格子疊加起來獲得的,並將每一個位置當作一個獨立的遊戲來計算SG函數,就能夠套用常規的博弈題思路了。根據遊戲規則,咱們有$$SG(i) = \mathop{mex} \limits_{1 \leq k \leq N / i} \{ \mathop{\oplus } \limits_{2 \leq t \leq k} \{ SG(t*i) \}\}$$(其中mex(S)表示S中沒有出現的最小天然數)按定義遞推就能夠拿到50分了。
考慮到當一個點i走到N要跳的步數必定時,咱們能夠把這些i的倍數的序列映射到另外一個序列2...N/i,這樣咱們就能夠用數學概括證實每一個點i的SG值只與從它跳到N須要的次數(即 N / i)有關。而後咱們能夠注意到,i從1到N中,N / i只會有O($\sqrt{N})$種取值,因此咱們只需遞推$O(\sqrt{N})$輪就能夠了。然而……在遞推時不管是維護一個指針線性遞推仍是用二分查找結構在線查找都只能拿到70分……
而後出題人kzf又告訴咱們,存在不少相鄰的按N/i劃分的區間有着相同的SG值(緣由大概是跳動次數增長時多跳的那一次改變的那些SG和不容易剛好等於增長以前的SG值?反正我不會證實……)。因此咱們在預處理時只要判斷是否能和上一塊合併就能夠了。複雜度……嗯……大概是O(玄學 × $N$)。不過實際跑起來仍是挺快的……
Update: 考慮上面說的70分算法,在遞推的過程當中咱們須要儘量快地查詢之前求出的SG值,那麼咱們直接用一個哈希表就能夠解決問題了!(我之前還沒寫過哈希表……太弱啦……)時間複雜度大概是$T(N) = \sum_{i=1}^{\sqrt{N}} (\sqrt{\frac{N}{i}} + \sqrt{i} ) × \frac{N}{P}$,這個求出來大概是$O(\frac{N^{\frac{7}{4}}}{P})$,總算是不用玄學完美地解決了= =
剛開始你有一個數字0,每一秒鐘你會隨機選擇一個[0,2^n-1]的數字,與你手上的數字進行按位或(C和C++的|,Pascal的or)操做。
選擇數字i的機率是p[i]。保證0<=p[i]<=1,∑p[i]=1
問指望多少秒後,你手上的數字變成2^n-1。
對於30%的數據,n<=10
對於60%的數據,n<=15
對於100%的數據,n<=20
考場上我寫了個錯誤的遞推,不過我機率論學得渣不知道爲何不對,總之我在考場上嘗試了好久都跑不出樣例,最終直接輸出個INF就放那了= =
換個思路,咱們嘗試用常規的指望的定義來求。設函數$f_k (S) $爲第k輪集合爲S的機率,那麼答案就是
$$\sum_{i=1}^{\infty} i * (f_i (U) - f_{i-1} (U) )$$
不難寫出函數f的遞推式:
$$f_{i+1}(S) = \sum_a \sum_b [a \cup b = S] f_{i}(a) * P(b)$$
不過這個式子看上去不太好轉移對吧?咱們能夠給它加個特技,不要管它們的並集是誰了,咱們直接來考慮等式兩邊S集合的全部子集的函數值之和(這步變換能夠經過集合論中的莫比烏斯反演來逆轉),即:
$$\sum_{s' \subseteq S} f_{i+1}(s') = \sum_{a \subseteq S} \sum_{b \subseteq S} f_i(a) * P(b)$$
或$$\sum_{s' \subseteq S} f_{i+1}(s') = (\sum_{a \subseteq S} f_i(a) ) (\sum_{b \subseteq S} P(b))$$
發現了什麼嗎?某一項在一個集合上的答案的子集和剛好等於前一項上同一集合的子集和與這一集合的初始機率函數(也就是f_1函數)的子集和的乘積。換句話說,若是咱們設$F_i (S) = \sum_{s' \subseteq S} f_i (s')$,那麼咱們的轉移方程就能夠寫成$F_{i+1}(S) = F_i (S) * F_1 (S) $。瞬間變得很是簡單有木有!!!什麼求和都沒有了,咱們馬上就能夠獲得F的通項公式:$F_i (S) = (F_1 (S)) ^ i$.
那麼如今咱們的$F_i$函數就已知了,咱們來看看怎麼由$F_i$函數推出$f_i$。咱們不妨令$f_i (S) = \sum_{S' \subseteq S} \mu(S', S) F_i(S')$,其中$\mu(S', S)$是咱們要求的莫比烏斯函數(注意這裏指的是集合論中廣義的莫比烏斯反演)。將F代入,可得
$$f_i(S) = \sum_{S' \subseteq S} \mu(S', S) \sum_{S'' \subseteq S'} f_i(S'')$$ 由容斥原理能夠得出,$\mu(S', S) = (-1)^{|S| - |S'|}$。從而咱們能夠獲得:$$f_i (S) = \sum_{S' \subseteq S} (-1)^{|S| - |S'|} F_i(S')$$.代入$F_i$(S')的通項公式,可得:$$f_i(S) = \sum_{S' \subseteq S} (-1)^{|S| - |S'|} (F_1 (S')) ^ i)$$
那麼咱們的最終答案就能夠表示爲
因爲F函數不會超過1,可直接利用冪級數求和得出答案:$$ \sum_{S' \subseteq S} (-1)^{|S| - |S'|} * ( \frac{1}{F_1(S') - 1} ) $$
而計算一個函數的子集和函數能夠用標程中給出的代碼用$O(n2^n)$的時間複雜度求出。這樣,這道題就完美解決啦!
你有一個長度爲n的數字串。
定義f(S)爲將S拆分紅若干個1~m的數的和的方案數,好比m=2時,f(4)=5,分別爲4=1+1+1+1, 4=1+1+2, 4=1+2+1, 4=2+1+1, 4=2+2
你能夠將這個數字串分割成若干個數字(容許前導0),將它們加起來,求f,並求和。
好比g(123)=f(1+2+3)+f(1+23)+f(12+3)+f(123)。
已知字符串和m後求答案對998244353(7*17*223+1,一個質數)取模後的值。
對於30%的數據,字符串長度不超過5
對於60%的數據,字符串長度不超過18
對於100%的數據,字符串長度不超過500,m<=5
不難看出,$f(i) = \sum_{j=1}^m f(i-j)$.很容易把這個遞推式寫成一個m × m的矩陣M。暫時撇開f函數前m項構成的向量$F_0$,咱們考慮對這整個轉移矩陣作dp。設g(i)表示可以將$F_0$轉移到$F_{num_{0, i}}$的轉移矩陣。其中$num_{i, j}$表示字符串的第i+1到j位構成的十進制數。
根據矩陣乘法對加法的分配律,能夠獲得$g(i) = \sum_{j = 0}^{i-1} g(j) * M ^ {num(j, i)}$,先用十進制矩陣快速冪的思路求出F的10的各冪次的冪,而後dp求出最終的矩陣,最後左乘向量求值便可。總複雜度$O({len}^2 m^3)$ 。值得注意的是……這題卡常數,矩陣乘法必定要儘可能減小取模的次數。