AquaMoon and Two Arrays
因為要求每一次操作后數都要大於 \(0\), 於是我們每一次選一個大於其目標值的數把它減一,選一個小於其目標值的數把它加一即可。
AquaMoon and Stolen String
我們發現答案串的每一個字母顯然出現了奇數次,而其他字母也只能出現偶數次,於是我們把每一列出現奇數次的字母提出來就是答案了。
AquaMoon and Strange Sort
顯然每一個數的初始位置與最終位置的距離必然為偶數。
於是偶數位置的數交換后還是只能在偶數位置,奇數位置的數交換后還是只能在奇數位置。
於是我們把偶數位置的數排一遍序,奇數位置的數排一遍序,如果原數組有序了,那么說明可以。
(實在是不知道為啥比賽的時候有一堆樹狀數組做法啊)
AquaMoon and Chess
我們發現一次移動可以看作是這樣:我們把 \(i\) 要跳過的 \(1\) 往 \(i\) 跳的方向移動一格,\(i\) 位置的 \(1\) 只往它要跳的方向移動一格,這樣效果是一樣的。
於是我們發現操作變成了選相鄰兩個 \(1\) 把它們往左/右移動一格(但 \(1\) 不能重疊)。
於是我們相鄰兩個 \(1\) 分一組,並且分出盡可能多的不相交組。
我們再魔改一下這個操作,我們只移動這些組,每次移動相當於把移動方向的下一個數移到這個組后面去,可以發現操作還是等價。
於是我們發現問題變成了把若干個全 \(1\) 組往里面插入,隨便組合數一下就行了。
AquaMoon and Permutations
首先如果一個數在一列只出現了一次,那么它所在的排列必然要在答案中。
於是我們不斷提出這樣的排列,把與它在同一位置有公共元素的排列刪掉,由於原來的答案排列都能配對至少一個新增排列,所以每確定一個排列,都至少有確定的排列個數這么多個排列被刪除。
於是我們每一次排列數減至少兩個,值域減小一個,遞歸成子問題。我們這么做,直到每一個數在一列中均出現兩次。
然后我們來證一個奇妙的東西(證明可能不太嚴謹):當每一列,每一種數僅出現兩次時,新增排列組可以取出若干互不相交的集合,原排列組也對應取出若干互不相交的集合使得,把任意一些對應集合互換,得到的排列組依然是拉丁方,並且這些集合是極小的,那么任意一種方案都可以通過這些替換來得到。
令 \(A\) 數組為剛開始的排列組,\(B\) 為新增的排列組;
且我們存在:
其中 \(S_i\) 可以替換 \(T_i\)。
若存在 \(S_i\cap S_j = X\),\(T_i\cap T_j = Y(i\ne j)\),\(|X|,|Y|\) 不同時為空。
我們令 \(S_i\) 中排列的第一個數形成的集合為 \(M_i\),\(S_j\) 為 \(M_j\),\(T_i\) 為 \(N_i\),\(T_j\) 為 \(N_j\),\(X\) 為 \(M\),\(Y\) 為 \(N\),則顯然 \(N=N_i\cap N_j\)。由於 \(A\) 中的第一位兩兩不同,如果 \(|X|>|Y|\),則顯然 \(|M_i\cup M_j|=|M_i|+|M_j|-|M|<|N_i|+|N_j|-|N|=|N_i\cup N_j|\),發現替換后數的種類變少了,不可能替換成功。
若 \(|X|<|Y|\),由於 \(|N|=|Y|\),則 \(N\) 中一定有數不出現在 \(M\) 中的。則它們一定要出現在 \(M_i\setminus M\) 與 \(M_j\setminus M\),出現了三次,矛盾。
若 \(|X|=|Y|\),如果 \(M\) 中有數重復,則還是有數出現三次。可推得 \(M=N\),且 \(M_i\setminus M=N_i\setminus N\),\(M_j\setminus M=N_j\setminus N\) 中。第一個數是這樣,其他的數也同理。則可以分為三個集合 \(S_i\setminus X\),\(S_j\setminus X\),\(X\) 來取代 \(T_i\setminus Y\),\(T_j\setminus Y\),\(Y\)。
因此任何一種替換都可以由若干不相交的極小的替換的組合而成。而這些極小替換直接顯然獨立,任意一種組合的替換都是合法的。
於是我們隨便挑一個排列,存在一個排列與它配對,把它刪掉,或者把與它配對的排列刪掉,再縮小排列組,最終得到的集合是一樣的(因為被刪除的集合肯定是原排列的某集合和它的替換集合)。我們把它刪掉,縮小,把答案乘 \(2\) 就行。
這樣復雜度就能 \(O(n^2)\) 了。
AquaMoon and Wrong Coordinate
我們發現我們差分一下,就能發現哪一行有問題,因為每一行的和必然為等差數列,把差不對的提出來就行。同時我們可以知道這一行正確的和是什么。
然后我們發現我們要找具體是這一行的哪一個不對,於是我們求出每一行的平方和,原數組平方和是 \(\sum_{i=1}^n x_i^2\),運行 1s 后應該為 \(\sum_{i=1}^n x_i^2+2x_iv_i+v_i^2\),差分一下是 \(\sum_{i=1}^n 2x_iv_i+v_i^2\),於是差分數組應該是等差數列,我們直接把差分數組再差分,得到 \(\sum_{i=1}^n 2v_i^2\),然后用這個把不對的位置修正一下,於是我們得到了這一行位置正確的平方和。我們知道正確的和與平方和,就很容易逆推出哪一個出了問題了。
AquaMoon and Time Stop(easy/hard)
這是一道數據結構練習題。
我們發現我們可以按時間掃描,把這一時間的每個位置的答案都搞出來。
我們發現當一個被禁止的區間出現時,中間的所有位置答案全部變成無窮。
當一個被禁止的區間消失時,會有若干區間又空了出來。我們用這個區間兩側的區間的答案來更新中間的答案(如果兩側區間都是無窮就不用管它,所以至多只有兩個這樣的區間)。我們發現有這么兩種情況:
一個是兩側的區間分別貢獻了中間區間的一點答案,答案顯然形成了兩段等差數列。
一個是一側的區間就貢獻了所有答案,甚至會影響另一側的區間。
當一段區間兩側不出現區間增刪的情況,我們發現經過若干秒它自己的答案直接平移秒數這么多格,然后在左邊補一個等差數列,右邊多的直接刪去。
我們發現操作都是形如插入/刪除等差數列的形式,於是我們直接用平衡樹維護即可。
對於上面的情況二,我們直接暴力修改被影響的區間,因為每次只會加常數個區間,修改會刪除若干區間,消耗時間是刪除區間的個數,於是復雜度是 \(O(nlogn)\)。
AquaMoon and Potatoes
以下是老K的神仙做法()
我們先直接把 \(b\) 和 \(c\) 換掉,然后變成了 \(b_i=a_j=c_k\)。
考慮一個簡單的線性 DP:
for i=1 to x:
ans+=s2[c[i]];s2[a[i]]+=s1[a[i]];++s1[b[i]];
然后我們設置 \(\sqrt n\) 個斷點,每個斷點把 \(s1,s2,s3\) 暴力存下來。
對於每一塊,我們把答案 \(s1[x],s2[x],s3[x]\) 寫成向量(每個值都記一個向量),經過中間一串數相當於左乘矩陣。
修改我們直接把這一段的矩陣暴力改掉,把后面塊被影響的向量也暴力改掉。
查詢我們整塊的部分對於每一個值已經有答案了,求和就行,零散塊只會影響 \(\sqrt n\) 個位置的值,暴力改掉就好。
復雜度 \(O(n\sqrt n)\),比較好寫(也許),還可以強制在線()
UPD: 注意常數(
