1. 程式人生 > >【清北學堂2018-刷題衝刺】Contest 1

【清北學堂2018-刷題衝刺】Contest 1

Task 1:最小公倍數

輸入n,求n與246913578的最小公倍數。

結果對1234567890取模。

【樣例輸入】

3

【樣例輸出】

246913578

【資料規模和約定】

  • 對於30%的資料, n<=10^9
  • 對於100%的資料,n<=10^18
  • 對於100%的資料,n<=10^100000

可以得到246913578和1234567890具有倍數關係,所以答案只有5種:

  • 246913578*{0,1,2,3,4}

求最小公倍數可以轉化為求最大公約數,也就是:

  • (n*246913578%gcd(n,246913578))%1234567890

因為乘法會爆longlong,所以我們可以把它轉成:

  • 246913578*((n/gcd(n,246913578))%5)

對解決不了的高精度部分做一個特判0/5處理,再加上一個隨機化騙分,80就到手了qwq

正解:

對於這個高精度數,可以認為它是通過多位數字構造組合起來的數,滿足加法原理和乘法原理。

所以我們只需要每一次獲取這個數的一位並取模就可以得到模意義下的這個數,在數字構造的時候直接求gcd取模即可


Task 2:不可逆轉

求有多少1~n的排列滿足:這個排列是波動的。

用a[i]表示排列中的第i個數,波動的意思是,對任意1<=i<=n-2,

若a[i]<a[i+1],則a[i+1]>a[i+2]
若a[i]>a[i+1],則a[i+1]<a[i+2]

答案對m取模

【樣例輸入】

3 15

【樣例輸出】

4

【資料規模和約定】

  • 對於30%的資料, n<=10
  • 對於60%的資料, n<=100
  • 對於100%的資料, n<=1000,m<=10^9

這個題目實際上是山東省選的一個原題,原題叫做地精部落,實際上就是求波動數列的個數。

在原來的題解裡面我見過一些非常玄學的解法,實在想不明白,直到看到這個題目的講解才明白這個題目有更好的想法。

大致思路是這樣的:

  • 設計一個狀態f[i]表示1-i的排列裡面波動數列的個數,然後取出i+1向原數列中插入。
  • 由於上升和下降本質一直,可以對稱得到所以只求一個方向就可以。
  • 由於每個數不同,最大值左右兩邊數列(大小為k-1和n-k)可以離散化為[1,k-1][1,n-k]兩個已解決數列。
  • 對一個確定的數列方案數為f[k-1]*f[ n-k ]。其間數字可以互換,考慮在n-1個數裡拆出這兩個數列的方案數,為C(k-1,n-1)。
  • 可以得到對於每一個位置k,方案數為f[k-1]*f[n-k]*C(k-1,n-1),總方案數就是f[n]=Σ(k為奇數/偶數)f[k-1]*f[n-k]*C(k-1,n-1)了

嗯,寫起來相當簡單,但思考起來就不是了。


Task 3:數值微分

【問題描述】
在數學中,對光滑函式求微分是一種常見的操作。在實際應用中,一些函式沒有解析形式,通常會從函式上取若干個點,用這些點來近似地表示這個函式。
現在有一個函式f(x),我們在函式上取n個值f(1),f(2),…,f(n)。對函式f(x)取微分得到函式f’(x)。我們近似地認為f’(i)=f(i)-f(i-1)。
同理,對f’(x)求微分可以得到f’’(x),我們近似地認為f’’(i)=f’(i)-f’(i-1)。(注意這裡的f’(i)和f’(i-1)本身就是我們求的近似值)。
函式f’(x)被稱為一階微分,f’’(x)被稱為二階微分。如果對函式f(x)連續做m次微分操作,得到的函式被稱為m階微分。特殊地,f(x)可以被認為是自身的0階微分。
用fm表示f(x)的m階微分,我們認為對任意自然數m,有fm=0。在計算近似值時,直接使用這條性質。
現在,給出f(1),f(2),…,f(n),以及m。,求fm, fm,…, fm
--------------------------
把上面所說的內容說的清楚一點,輸入的是f(1),f(2),…,f(n)

  • 令f0=f(x),x=1,2,…,n
  • 令fi=0,i=0,1,…m
  • 令fi=fi-1-fi-1, x=1,2,…,n, i=1,2,…,m
  • 輸出的是fm ,x=1,2,…,n

【輸入格式】

第一行兩個數n,m

第二行n個數f(1),f(2),…,f(n)

【輸出格式】

輸出n行,第x行是f[m](x)。  

結果對100007取模

【樣例輸入】

3 2

6 7 8

【樣例輸出】

6

100002

0

【資料規模和約定】

  • 對於30%的資料, m<=1000
  • 對於60%的資料, m<=10^6
  • 對於100%的資料, n<=1000,m<=10^9,0<=f(i)<100007

    題目意思其實蠻簡單的,就是求f[ i ][ j ]=f[ i-1 ][ j ]-f[ i-1 ][ j-1 ],一個類似於楊輝三角的遞推。
    經過手推我們會發現其實所謂m階微分就是(a-b)^m的多項式展開,也就是求Σ(-1)^i*C( m , i )。
    想到這裡就不難處理了,但是緊接著的問題還有一個,就是應該怎麼求組合數。
    對於這個題目,m和n的範圍差距懸殊,而且無論怎麼樣單次計算組合數都會超時。考慮到組合數較大項一定為m,較小項範圍為[ 1 , n ],且n的範圍為1000,m的範圍為1000000000,我們需要用一種高效的求法。
    先複習一下組合數的求法有哪些吧。
    • 硬算 單次O( max( n , m ) )
    • 階乘逆元求法 適用於多次查詢,複雜度預處理O( nlogn ),查詢接近O( 1 ),但是模數必須是質數。(100007不是質數)
    • 楊輝三角遞推求法 適用於多次密集小範圍查詢,複雜度預處理O( n^2 ),查詢O( 1 )
    • 費馬小定理/exgcd求逆元 單次O( n+logn ),是最簡單的方法,模數必須為質數
    • 階乘分解求逆元 適用於高精度組合數計算,或者模數不為質數的求法。複雜度預處理O( nlogn ),查詢O( 1 )

    雖然寫起來稍微有點麻煩,但階乘分解確實是唯一可行的方法了。所以基礎打牢還是相當重要的啊QWQ