1. 程式人生 > >「泛做題解」曾經的 AtCoder 題解匯總

「泛做題解」曾經的 AtCoder 題解匯總

子序列 有用 ext 是否 單位 暴力枚舉 同余 += coder

註:此博客寫於 2017.8 ~ 2017.11

一個小清新OJ.

題意簡短,超贊!

題目新穎,超贊!

解法巧妙,超贊!

標程簡潔,超贊!

AtCoder Regular Contest 068

E - Snuke Line 給定\(n\)個區間\([l,r]\)和一個數\(m\)。對於\(d=1,2,3…,m\),求\(kd(1 \leq kd \leq m,k\in Z)\)被多少個不同區間覆蓋(對於不同的\(k\),只算一次)。\(1 \leq n,m \leq 3\times 10^5,1 \leq l \leq r \leq m\)

記區間的長度為\(len=r-l+1\)。想到可以\(O(mlogm)\)

暴力枚舉所有的\(kd\),用線段樹算出它被幾個區間包含。容易發現當\(d<len\)時,有可能被多次計算。

考慮當\(d \leq len\)時,則一定存在\(k\)使得\(kd\)被這個區間覆蓋。於是我們記錄滿足\(d \leq len\)的區間個數即可。而對於\(d>len\)的情況,至多有一個\(kd\)被區間覆蓋,於是就可以用線段樹維護。即當\(d>len\)時加入這個區間,同時單點詢問\(kd\)被多少個區間覆蓋。復雜度\(O((mlogm+n)logm)\)

Code

F - Solitaire 有一個雙端隊列,依次往首或尾插入數1到n。然後你可以從隊列的首或位取出一個數,順次相接組成一個序列。求有多少個序列的第\(K\)

位為\(1\)\(1 \leq k \leq n \leq 2\times 10^3\)

顯然,當\(n\)個數全部插入後,隊列一定是遞減到1再遞增的。不難發現,得到的序列的前\(K\)位,一定是由兩個遞減序列交錯得到的,且第\(K\)位為1。

\(n\)\(1\)逐個考慮每一個數是否選擇,且屬於哪一個序列。定義\(f(i,j)\) 已經得到了序列的前\(i\)位,其中第\(i\)位為\(j\)的方案數。將\(j\)加入序列1,則\(f(i,j)\)可由\(f(i-1,k), k>j\)轉移過來。

如果將新的數加入序列2,該如何轉移?可以發現,這個數一定是沒選擇的數中最大的數(序列2也是遞減的)。

\(f(i,j)\)可由\(f(i-1,j)\)轉移過來。

事實上,DP的過程還有一個非法的轉移。\(f(K-1,1)\)會轉移到\(f(K,1)\),不是以1作為第\(K\)個數。

對於剩下的\(n-K\)個數,每次可以取頭或尾。於是答案\(ans=(f(K-1,1)-f(K-1,1))\times 2^{n-K-1}\)。 時間復雜度\(O(nK)\)

Code

AtCoder Regular Contest 069

E - Frequency\(n\)堆石頭,第\(i\)堆有\(ai\)個石頭。每一次,你需要記錄下石頭最多的堆的序號(當石頭數相同時,取最左端的),然後你可以從某堆中拿走一塊石頭。直到石頭被全部拿走。需要使得序號組成的序列字典序最小,問1到n在序列中出現的次數。

可以發現,這個序列一定是非遞增的。假設現在最多的石頭堆為\(x\),在1到x-1中石頭最多的堆為\(y\)。考慮貪心的過程,我們需要把x到n中,石頭數大於\(ay\)都取到\(ay\),因為這樣能使得序號盡可能快地減小。離散化石頭數,再從小到大考慮,用樹狀數組維護小於某個值的石頭堆數量,以及石頭數總和即可。

事實上,存在排序後\(O(n)\)的做法。

Code

F - Flags 你在一條線上插\(n\)\(flag\),其中第\(i\)\(flag\)可以插在\(xi\)\(yi\)。記所有\(flag\)兩兩間的距離最小值為\(d\),求\(d\)的最大值。

暫未編寫。 考慮二分答案\(d\)。於是是否放在\(xi,yi\)變成了\(2-SAT\)判定性問題,對於\(xi\)\(yi\)恰好放一個,距離小於\(d\)的位置不能同時放,構成了一些約束條件。暴力枚舉所有點對,可以在\(O(n^2logMAX_{x})\)的時間內解決。

發現許多約束條件是無用的。考慮類似線段樹的分治結構來建圖,對於每個點,至多與\(O(logn)\)個區間相連;令一方面,線段樹中父子相連的邊也只有\(O(n)\)條。單次判定的復雜度可以做到\(O(nlogn)\)。總的時間復雜度\(O(nlognlogMAX_{x})\),可以通過此題。

存在\(O(n(logn+logMAX_x))\)的算法,暫未理解。

AtCoder Regular Contest 070

D - Need 給定\(n\)個數\(ai\)。如果存在子集滿足其和大於等於\(K\),則稱為是好的子集。如果一個數\(ai\)所在的所有好集中,去除\(ai\)後仍是好集,則\(ai\)是無用的。求無用的數的個數。

對於\(x<y\),若\(y\)是無用的,則\(x\)一定無用的,所以答案滿足單調性。考慮判斷\(x\)是否是無用的,用\(bitset\)維護\(n-1\)個數相加能組成的集合(\(x\)除外,可以用類似\(DP\)的方式求出)。

顯然,如果其他的數能組成\(K-x\)\(K-1\)中的任意一個數,則\(x\)是有用的。時間復雜度\(O(\frac {n^2logn} w)\) ,此處\(w\)一般為\(32\)\(64\)

Code

AtCoder Regular Contest 071

E - TrBBnsformBBtion 有字符串\(S,T\),僅由\(A\)\(B\)構成。有如下操作:①選擇一個字符:\(A\rightarrow BB\)\(B\rightarrow AA\)。②刪除連續3個相同的字符:\(AAA\)\(BBB\)。給定\(Q\)個詢問,對於每個詢問,回答\(S[a,b]\)能否變換為\(T[c,d]\)\(|S|,|T|,Q \leq 10^5\)

想了幾分鐘就YY了一個結論:把A看作1,把B看作2,兩個串能變換當且僅當兩個區間和模3同余。然後就A掉了。首先,必要性顯然,因為對於區間和模3,不論如何操作都不會改變。

看了官方題解才知道如何證明充分性。首先主要到所有的操作都是可逆的:\(A\rightarrow BB\rightarrow AAAA\rightarrow A\)。且\(A,B\)可以任意地加3個或減3個。考慮將\(S\)\(T\)中的\(B\)全變為\(A\)。如果\(S,T\)\(A\)個個數關於3同余,則一定能變換。就證明了結論。

Code

F - Infinite Sequence 給定\(n\ (n \leq 10^6)\),問存在多少個無窮序列滿足:1.每個數都在1到\(n\)之間。2.對於任意\(n \leq i,j\),都有\(a_i=a_j\)。3.對於任意的\(i\),若存在\(i+1 \leq j<k \leq i+a_i\),都有\(a_j=a_k\)

發現只有前\(n\)位是有用的,考慮到動態規劃更容易向前轉移,定義\(f(i)\)為子序列\([i,n]\)滿足條件的個數,於是我們考慮\(a_i\)的值即可轉移。

  • 發現1是一個比較特殊的數,當\(a_i=1\)時,\(f(i)=f(i-1)\)
  • \(a[i]\not=1,a[i+1]\not=1\)時,序列為\(ABBBBBB…\)的形式,\(f(i)=(n-1)\times (n-1)\)
  • \(a[i]\not=1,a[i+1]=1\)時,序列為\(A,1,1,,..,1,B…\)的形式,\(f(i)=f(i-3)+f(i-4)+…+f(1)+n-i+2\)

Code

AtCoder Regular Contest 072

D - Alice&Brown A和B在玩一個遊戲。一開始,有兩堆石子分別有\(X\)\(Y\)個。你可以從一堆中取\(2i\)個,然後放\(i\)個到另一堆。無法操作的玩家輸。問先手是否存在必勝策略?\(0 \leq X,Y \leq 10^{18}\)

通過打表發現,當\(|X-Y|>=2\)先手必勝,否則後手必勝。考慮如何證明。

  • 對於\((X,Y)=(0,0),(0,1),(1,0),(1,1)\),滿足\(|X-Y|<=1\),是必敗態。

  • 對於必勝態,設\(|X-Y|=3k+r>=2\ (r=0,1,-1,\ k>=1)\) ,取\(i=k\),即可轉移到必敗態。
  • 對於必敗態,操作後\(X-Y\)至少改變3,一定會轉移到必勝態。

Code

E - Alice in linear land 給定長度為\(n\)的操作序列\(ai\)和距離\(di\)。對於每個\(ai\),當\(|d-ai|<d\)\(|d-ai|\)會成為新的\(d\),若最終\(d=0\),則稱是可達的。給定\(Q\)個詢問\(qi\),問能否改變\(a[qi]\),使得操作序列是不可達的?\(n,Q \leq 5\times 10^5\)

首先可以預處理前綴\(a[1,qi-1]\)操作後的\(d\),記為\(pre[qi-1]\)。發現對於詢問\(qi\),只需要知道後綴\(a[qi+1,n]\)使得序列不可達的最小的\(d=suf[qi+1]\),只要\(pre[qi-1]>=suf[qi+1]\)就一定能做到。

於是問題轉化為如何就\(suf[i]\)。顯然,\(suf[n+1]=1\),而且隨著\(i\)的減小,\(suf[i]\)一定是非遞減的。當\(ai>=2\times suf[i+1]\),可以取到\(suf[i]=suf[i+1]\)(此時無法執行操作);否則\(suf[i]=suf[i+1]+ai\)

Code

F - Dam 有一個水壩容積為\(L\),一開始沒有水。此後\(n\)天,在第\(i\)天早晨,會進來體積為\(Vi\),溫度為\(Ti\)的水;為了下一天水不會溢出,第\(i\)天傍晚需要排出一些水。對於體積\(V1\),溫度\(T1\)和體積\(V2\),溫度\(T2\)的水混合,體積為\(V1+V2\),水溫為\(\large \frac {T1\times V1+T2\times V2}{V1+V2}\)。回答\(n\)個詢問,對於第\(i\)個詢問,輸出在第\(i\)天能夠達到的最大水溫。\(n \leq 5\times 10^5\)

假設混合得到的水體積為\(V2\),溫度為\(T3\)。由題目可知\(T1\times V1+T2\times V2 = T3\times V3\)。考慮將\((x,y)=(V,TV)\)抽象為一個向量,那麽,水的混合就變成了向量之和!

觀察這個向量,發現\(T\)對應的就是它的斜率!將水排出,相當於是原向量乘上<1的實數!將可能的狀態畫在坐標系上,可以發現這一定是一個上凸包。如圖(555...圖丟了,湊合腦補一下)

而新加入一個向量後,最右端的會被刪除。此時不一定還是凸包,在左端比較相鄰的斜率,合並即可。

整個過程用雙端隊列維護,復雜度\(O(n)\)

AtCoder Regular Contest 073

Code

E - Ball Coloring\(n\)個包,每個包裏各有兩個球,權值為\(xi\)\(yi\)。你需要將一個球塗為紅色,另一個球塗為藍色。令\(Rmin\)為紅球中的最小權值,\(Rmax,Bmin,Bmax\)同樣定義。求出\((Rmax-Rmin)\times (Bmax-Bmin)\)的最小值。\(n \leq 2\times 10^5\)

假設所有權值中的最大值為\(Max\),最小值\(Min\)。不失一般性地,有兩種情況:

\(Rmax=Max,Bmin=Min\),此時需要最大化\(Rmin\),最小化\(Bmax\),於是將兩個球中較大的塗為紅色,較小的塗為藍色。

\(Rmax=Max,Rmin=Min\)(Min和Max不在同一包裏),此時需要最小化\(Bmax\),最大化\(Bmin\),令\(xi \leq yi\),之後按照\(x\)升序排序。我們說,最優方案一定是,排序後,前\(k\ (1 \leq k \leq n)\)個的\(xi\)塗為紅色,後\(n-k\)個塗為藍色。如何證明,考慮反證法。

假設第\(p(p>=k+2)\)塗為了紅色,那麽\(Bmin\)並不會增大,而\(Bmax\)並不會減小,所以一定不會是更優解。於是簡單證明了結論。

Code

F - Many Moves 在一根長度為\(n\)的數軸上,有兩個方塊,位置為\(A,B\)。並且在同一時刻,你能移動一塊方塊一個單位距離。你需要依次到達位置\(xi\),求最少所需時間。\(n,Q \leq 2\times 10^5\)

\(xi\)作為階段,註意到上次的一個方塊位置一定是在\(x[i-1]\),於是不難想到\(O(n^2)\)的DP。\(f[i,j]\)表示到位置\(xi\),另一個位置為\(j\)的最小時間。若原來位置為\(x[i-1]\)的到位置\(xi\),即有\(f[i,j]=f[i-1,j]+|x[i]-x[i-1]|\)。否則即有\(f[i,x[i-1]]=f[i,j]+|j-x[i-1]|\)

考慮如何從優化轉移的時間。對於前面的狀態轉移方程,事實上就是線段樹的區間加。對於後面的狀態轉移方程,考慮維護\(f[i,j]-j\)\(f[i,j]+j\)的值,在\([1,x[i-1]]\)\(f[i,j]-j\)的最值;在\([x[i-1],n]\)\(f[i,j]+j\)的最值即可。階段間的轉移優化到了\(O(logn)\)

Code

AtCoder Regular Contest 074

D - 3N Numbers 給定\(3n\)個數\(A\),你需要刪除其中的\(n\)個數,使得剩下\(2n\)個數\(A‘\)中前\(n\)個數之和-後n個數之和之差最大。求最大值。\(n \leq 10^5\)

發現對於刪除後\(A‘\)的第\(n\)個數一定是在原來\(A\)\([n,2n]\),考慮暴力枚舉\(A‘[n]\)的取值,剩下的貪心地選取。整個過程用堆維護。

Code

E - RGB Sequence 您需要構造一個長度為\(n\), 由R,G,B構成的序列,滿足以下\(m\)個限制。對於限制\(i\),滿足\([li,ri]\)間不同的顏色種數恰好為\(xi\)。求滿足條件的序列數。\(n,m \leq 300\)

考慮到如果存在不滿足的情況,一定是DP過程中最後的R,G,B發生沖突。於是考慮狀態\(f[R][G][B]\)表示\(R,G,B\)最後的位置,發現當前位置\(p=max\{R,G,B\}\)。考慮暴力轉移,轉以後判斷是否沖突即可。

Code

AtCoder Regular Contest 075

D - Widespread\(n\)只怪獸,第\(i\)只怪獸初始血量\(hi\)。每次可以選定一只怪獸攻擊,造成\(A\)點血量的傷害。同時其他怪獸受到\(B\)點血量的傷害。求最少的攻擊次數。\(n \leq 100000\)

考慮二分答案次數\(T\)。當某只怪物的血量\(hi \leq BT\)時,不需要主動攻擊。否則需要\(\large \lceil \frac {hi-BT} {A-B}\rceil\)次主動攻擊,判斷主動攻擊次數之和是否不超過\(T\)次即可。

Code

F - Mirrored 對於一個正整數\(n\),記\(rev(n)\)\(n\)的倒置,例如\(rev(123)=321,rev(4000)=4\)。給定\(D\),求存在多少\(n\)滿足\(rev(n)=n+D\)\(D \leq 10^9\)

以5位數為例,\(\overline{edcba}-\overline{abcde}=9999(e-a)+990(d-b)\) 考慮到如果\(D\)不是9的倍數,一定無解,否則我們考慮現將\(D\)除以9。然後DFS,發現\((e-a)\ mod\ 10\)可以確定,同樣可以逐位確定剩余的位,最後乘法原理確定總方案數即可。註意奇偶分類。

Code

AtCoder Regular Contest 075

E - Connected? 給定\(R \times C\)棋盤上的\(n\)對點,要求這\(n\)對點彼此連線,保證這些線不相交。求是否存在方案滿足。

考慮到,如果不是兩個點都在邊界上,一定存在方案。所以我們只要考慮邊界點即可。考慮使用一個棧,順時針處理所有的點\(x\),如果棧頂的點是\(x\),則出棧,否則令\(x\)入棧。最後只要檢查棧是否為空即可。

Code

AtCoder Regular Contest 077

D - 11 給定\(n\)和長度為\(n+1\)的子序列,每個數都在\([1,n]\),且恰有一個數出現兩次。對於\(k=1,2,...,n+1\),求出長度為\(k\)的互異子序列個數。\(n \leq 10^5\)

首先找出相同的兩個數\(x\)的位置\(l,r\),可以發現剩下的數都是等價的。對於每個\(k\),分類討論計數。按照選取\(x\)個數,就是\(C_{n-1}^k+2C_{n-1}^{k-1}+C_{n-1}^{k-2}\)。註意到,如果在\((l,r)\)內沒有選數,選擇\(l\)和選擇\(r\)會被當作同一情況,於是答案還要減去\(C_{u+v}^{k-1}\)

E - guruguru 有一盞燈具有\(1,2,...,m\)種亮度。遙控板可以一次操作可以將亮度加一(為\(m\)時,變為\(1\))或跳轉到固定的亮度\(x\)。一開始亮度為\(a_1\),接下來\(n-1\)次,你需要將亮度從\(a_{i-1}\)調節到\(a_i\)。選取一個\(x\),使得調節的總次數最小。\(n,m \leq 10^5\)

\(f(x_0)\)為:當\(x=x_0\)時,需要調節的總次數。考慮亮度\(s\Rightarrow t\)\(f(x)\)的貢獻(假設\(s<t\), 其他情況同樣處理)。

  • 對於\(x \leq s\)\(f(x)+=t-s\)
  • 對於\(s<x \leq t\)\(f(x)+=t-x+1\)
  • 對於\(t<x\)\(f(x)+=t-s\)

發現是區間操作,並且只有在最後查詢。於是考慮差分,特別的,需要分為常數部分和系數部分。

F - SS 定義“雙串”,由兩個相同的字符串拼接而成。定義\(f(S)\),在雙串S後追加最少字符得到的雙串。給定\(S0S0\)\(l,r\)。求\(f^{10^{100}}(S0S0)\)\([l,r]\)內,26個字母分別出現的個數。\(|S|<=2*10^5,l,r \leq 10^{18}\)

有待更深入理解。用KMP預處理Next[],可以的到S0的最短相同前後綴T,設\(f(S0S0)=STST\)。通過畫圖發現,若\(|T|\)\(|S|\)的因數,那麽S就是由一些T拼成的,\(f(STST)=STTSTT\)。否則,\(f(STST)=STSTST\)。設\(g(S)g(S)=f(SS)\) ,能得到\(g^{i+2}(S)=g^{i+1}(S)+g^i(S)\)(顯然,對於\(i\)無限大時也滿足第一種情況)。考慮求出前綴的貢獻,按照類似fib數列的遞推方式計算即可。

「泛做題解」曾經的 AtCoder 題解匯總