河南省隊胡扯第一場解題報告

     不提早完成任務的報應就是這樣……昨天晚上熬夜趕題面捏數據,結果早上起來發現各類漏洞,最後兩題還沒時間捏數據了,算是完全失敗吧= =|||html

     先把題解寫出來,下午再慢慢捏數據好了。
算法

 A

     第一題大概意思是維護一個集合,要求實現兩種操做:添加一個元素 和 刪去其中較大的一半(注意是下取整)。最後還要求可以線性地輸出(雖然排序後再輸出沒有被卡掉……)。
數組

     算法一是直接用一棵平衡樹維護,由於每一個元素只可能被刪除一次,因此直接暴力刪除就能夠。
ide

     然而平衡樹常數比較大(雖然我已經沒有時間去造針對平衡樹的數據了……),能夠考慮用一個最大堆實現,刪除時直接依次彈出就能夠了。
idea

     我爲正解準備的數據範圍彷佛也不怎麼合理,只有10^7……其實這個算法是在《算法導論》攤還分析一節中的習題,咱們只須要維護一個無序數列,實現一個$O(|S|)$的刪除操做,而每次插入的時候直接將元素附加在數組末尾,就能夠在關於操做數呈線性的時間內完成全部操做了。這個一樣能夠經過「每一個元素只會被刪除一次」來證實——咱們能夠將每次刪除操做須要的時間附加在刪除的那些元素對應的插入操做上,因爲每次刪除的元素個數也是$O(|S|)$,很明顯全部刪除操做附加在插入操做上的時間是常數級別的。
spa

     對於無序數列的刪除操做能夠在《算法導論》上的「順序統計」一節找到。具體地,咱們能夠經過相似快速排序的隨機算法在線性的指望時間內求出須要刪除的最小的元素,將比這個元素小的元素所有移動到數組的前半部分就能夠了。code

 

 1 #include 
 2 #include 
 3 
 4  const  int maxn =  10000003;
 5 typedef  long  long LL;
 6 
 7  int A[maxn], *it = A, N;
 8  bool exist[maxn];
 9 
10  int main(){
11 #ifdef DEBUG
12     freopen( " test.txt "" r ", stdin);
13  #endif
14      int *i, M, *t, mid, a, x;
15     unsigned rnd, C;
16     scanf( " %d%d%u%d%u ", &N, &M, &rnd, &a, &C);
17     x = a;
18      while(M--){
19         rnd += (rnd <<  2) +  1;
20          if(rnd & C)*(it++) = x, x = (LL)x * a % N;
21          else{
22             t = A + (it - A +  1) /  2;
23             std::nth_element(A, t, it);mid = *t;
24              for(i = A;i < t;++i) if(*i >= mid)std::swap(*i, *(--it));
25             it = t;
26         }
27     }
28     printf( " %d\n "int(it - A));
29      for(i = A;i < it;++i)exist[*i] =  true;
30      for( int j =  1;j <= N;++j) if(exist[j])printf( " %d  ", j);
31     puts( "");
32      return  0;
33 }
View Code

B

     這題實際上是我把一個idea強行套在了一個經典算法上……因此數據範圍出得有點牽強,很是抱歉……
htm

     第一層數據範圍是強行留給只會倍增LCA的同窗的(好比一兩個個月前的我)。
blog

     第二層數據,因爲詢問次數比較大(不過我猜我仍是卡不掉倍增……),能夠先預處理出dfs序列,構造出ST表來實現$O(1)$查詢。
排序

     第三層數據……嗯……說出來大家不要打我啊!= = 咱們來看數據中的N,都符合$3 * 2^i$的形式,因此此中必有蹊蹺!觀察那個「強制在線」的遞推式,u_i = X^{\frac{N}{3} * Ans_{i-1} + k} * i \mod Nv_i = Y^{\frac{N}{3} * Ans_{i-1} + k} * i \mod N,能夠發現$\frac{N}{3}$剛好是$\phi(N)$的表達式。那麼遞推式就變成了這樣……

$u_i = X^{\phi(N) * Ans_{i-1}} * X^k * i \mod N$,或$u_i = X^k * i \mod N$。那麼咱們就能夠用Tarjan LCA離線作了……雖然數據範圍很怪異,可是……領會精神,領會精神……

C

     我思考了很久的idea竟被出成了這個鬼樣子……= =仍是數據範圍的問題,看來不先寫std真是不能亂定數據範圍啊= =

     算法一:$$F_i = 1 (i = 0 \mod M \lor i < M);$$

                $$F_i = F_{i-1} + F_{i-M}(otherwise)$$

直接遞推,不說了;

     算法二:算法一 + 高精度.(其實我實在不想加上這一層數據……)

     算法三:不難發現,從M開始,遞推式的選擇是以M爲週期的。嘗試把從0開始的數列中的元素每M個一行鋪成矩陣,那麼遞推式就能夠寫成這樣:

$$F_{i,j} = 1 (i = 0 \lor j = 0)$$

$$F_{i,j} = F_{i-1,j} + F_{i,j-1}$$

     發現遞推式很熟悉?沒錯這個數列其實就是組合數……具體來講是$F_{i,j} = \tbinom{i}{i+j} = \frac{(i+j)!}{i! j!}$ 用這裏介紹的階乘質因數分解 求組合數就能夠了。

相關文章
相關標籤/搜索