有一個長度爲n的數列ai,一開始將數列的前L個丟入隊列中。
一次操作是對於隊列中的每個數ai,有ai的機率有1的貢獻。設貢獻和爲x。
然後將隊列中前x個彈出去,再從數列中接着x個。
如果數列中的數取完了,操作停止。
問期望進行多少次操作。
思考歷程
一開始就看錯了題意,於是這就變成的了一道神仙題。
只想到了ai相等的情況。
由於時間不夠,寫出來之後調都不調就交了。
結果自然是爆0。
(話說我在寫這個東西的時候沒有用分治NTT……不知道是我的方法錯了,還是確實能不用分治NTT……)
正解
設fi爲當前隊列中的數在[i,i+L)中的期望。
轉移十分顯然,這裏就不寫了。
直接暴力轉移肯定不能過,接下來就是在這個東西的基礎上優化。
把整個序列倒過來做,fi就變成了當前隊列中的數在(i−L,i)中的期望。
設Pi=∏j=i−L+1i(1−aj+ajx)
隨便推一推得:
fi=1−[x0]P[i]1+∑j=1Lfi−j[xj]Pi
接下來問題是處理∑j=1Lfi−j[xj]Pi,其它的都很好辦。
設Fi=∑j=Lifjxj
於是∑j=1Lfi−j[xj]Pi=[xi](Fi−1Pi)
這下就好看很多了。
考慮分治NTT。假如現在要計算區間[l,r]的答案。
對於每個i∈[l,r],我們把Pi的公因數提取出來,就是∏j=r−L+1l(1−aj+ajx)
設Fl,r′=Fl−1∏j=r−L+1l(1−aj+ajx),這就是前面[1,l−1]區間對每一個i∈[l,r]共有的貢獻,可以一起算。
[xi]Fi,i′就是對fi的貢獻。
考慮如何從Fl,r′轉移至Fl,mid′和Fmid+1,r′
Fl,mid′=Fl−1j=mid−L+1∏l(1−aj+ajx)=Fl,r′j=mid−L+1∏r−L(1−aj+ajx)
Fmid+1,r′=Fmidj=r−L+1∏mid+1(1−aj+ajx)=Fl,r′j=l+1∏mid+1(1−aj+ajx)+(i=l∑midfixi)j=r−L+1∏mid+1(1−aj+ajx)
上面式子中的那堆連乘都是可以用分治NTT預處理的。
看起來這個東西並沒有優秀到哪裏去啊……
我們想要求的,僅僅是[xi]Fi,i′
對於Fl,r′,如果它一直轉移到了葉子節點,那麼乘上的多項式的次數是O(r−l)級別的。
我們最終只要對i∈[l,r]的所有i有用的項,這意味着有些次數很小的項,他們次數增高O(r−l)之後依然不會對任何i∈[l,r]的i產生影響,這個項就是沒用的。
對於沒用的項,那就可以忽略不計。
所以,只需要存最後O(r−l)項就可以了。題解說標程存了最後2(r−l+1)項。
於是這題就做完了,時間複雜度O(nlg2n)。
總結
一個晚上,兩個小時思考,再加一個小時寫博客整理思路。
這種到現在pty都沒有AC的題目,我不知道寫出來要多長時間。
就先把題解晾在這裏好了……
這題的精髓,除了亂推一波式子以外,我認爲是最後的那個保留最後幾項的那個操作。
我終於明白了原來分治NTT還能這麼搞。