51nod 1799 思維 二分 數論 分塊打表

2021-09-30 14:35:53 字數 3317 閱讀 5609

題目鏈結

很好的題目,很早就關注了此題,但一直沒看懂題解,今天在紙上模擬了很久終於了有了新的感悟

對於這種 求期望

∗n!m

od1e

9+

7求期望*n! \mod 1e9+7

求期望∗n!

mod1

e9+7

的問法實際上就是求方案數。

雖然數列完全打亂了,但其實對於二分結果的影響並沒有直觀上的那麼大。

形如下列數列:

1 2 3 4 5 6 7 8 9 10

下面讓我們來模擬二分查詢7的位置的過程:

第一次mid = 5 而因為 7 > 5 ,故右移 ⇒ l = mid+1 = 6

第二次mid = 8 而因為 7 < 5 ,故左移 ⇒ r = mid-1 = 7

第三次mid = 6 而因為 7 > 6 ,故右移 ⇒ l = mid+1 = 7

第四次mid = 7 而因為 7 == 7 故二分結束

從以上過程我們發現,我們查詢 7 的過程,實際上起作用的點只有 5,6,7,8,這些點決定了每一次二分的左移還是右移,那如果我們改變其他數的位置,形如:

1 3 4 25 6 7 89 10

或者1 2 10 45 6 7 83 9

只要不改變5,6,7,8的位置,無論其他數字置怎麼變化,結果都是一樣的。

從上面的模擬過程我們可以試著推出此題的結**式。

因為我們要求出每次二分結束後 r = k 的方案數,故我們可以模擬二分的過程,求出特殊點的個數(形如上例子5,6,7,8),由二分的性質,這樣的點一定不超過 log

nlogn

logn

個。考慮當 mid 在 k的右邊,此時我們需要左移,故必須滿足條件$ a[mid] <= m$

此時mid這個點就是乙個特殊點,因為其存在約束條件,值必須<=m

<=m

<=m

,統計此類點的個數為x,因為x個點的值各不相同且值只能在1~m之間,故則此類約束點的方案數為

c mx

c_m^x

cmx​

同理,對於需要右移的點,統計其個數為y,其約束條件是其值val

valva

l滿足 m

l<=n

m < val <= n

ml<=n

故方案數為:

c n−

my

c^y_

cn−my​

而對於沒有約束的點,因個數為(n−

x−y)

(n-x-y)

(n−x−y

)且可以隨意排列,故方案數為(n−

x−y)

!(n-x-y)!

(n−x−y

)!綜上所述:ans

=cmx

∗cn−

my∗(

n−x−

y)

!ans = c_m^x * c^y_ * (n-x-y)!

ans=cm

x​∗c

n−my

​∗(n

−x−y

)!公式有了,只剩最後乙個關鍵點就是n的範圍有1e9,而x,y的和最多只有log

(n

)log(n)

log(n)

也就是說我們需要求出 (1e

9)

!(1e9)!

(1e9)!

對於此題如果暴力時間複雜度是**的,離線預處理的話空間複雜度是**的。

此時就涉及了乙個神奇的方法,分塊打表。

我們可以將1e9

1e91e

9分成很多小的部分,比如分成一千塊的話每一部分只有1e6

1e61e

6,我們離線處理塊的值,即(1e

6)!,

(2e6

)!..

.(1e

9)

!(1e6)!,(2e6)!...(1e9)!

(1e6)!

,(2e

6)!.

..(1

e9)!

的階乘這樣的話,比如求(

3500000)!

(3500000)!

(35000

00)!

就可以看成 :

3 e6

!∗(3

e6+1

)∗(3

e6+2

)...

(3e6

+5e5

)3e6! * (3e6+1)*(3e6+2) ... (3e6+5e5)

3e6!∗(

3e6+

1)∗(

3e6+

2)..

.(3e

6+5e

5)因為( 3e

6)

!(3e6)!

(3e6)!

的值是已知的,故我們只需要暴力算後面的部分。

這樣每次暴力算的部分一定是小於 1e6

1e61e

6的,對於上例只需要求到5e5

5e55e

5。這樣就大大降低了複雜度,最後 15ms

15ms

15ms

就能過掉啦~

**:

#include

#include

#include

#include

#include

using

namespace std;

typedef

long

long ll;

const ll m =

1e6;

const ll mod =

1e9+7;

ll fac=

;//表太長,此處省略,想參考的朋友見部落格末尾

ll get

(ll x)

return res;

}int

main()

else

} ll ans =1;

for(ll i=m ;i>=m-x+

1;i--

) ans = ans*i%mod;

for(ll i=n-m;i>=n-m-y+

1;i--

) ans = ans*i%mod;

ans = ans*

get(n-x-y)

%mod;

printf

("%i64d\n"

,ans)

;return0;

}

//表

ll fac = ;

51Nod1799 二分答案

lyk最近在研究二分答案類的問題。對於乙個有n個互不相同的數且從小到大的正整數數列a 其中最大值不超過n 若要找乙個在a中出現過的數字m,乙個正確的二分程式是這樣子的 l 1 r n mid l r 2 while l r 最終a r 一定等於m。但是這個和諧的程式被熊孩子打亂了。熊孩子在一開始就將...

51nod1799 二分答案 分塊打表

分析 要走到乙個位置的話一共要往左或者往右走o logn 次,而且每一步都必須走對。因為對於題目中給出的 無論k是什麼樣的數,二分過程的次數都是固定的。每走一步只和ami d 的大小關係有關,因此有一些位置只能放 m 或者 m的數,其他 位置可以隨便放。階乘可 以分段打表。includeusing ...

二分 假 數論 分數

nput 第一行包含兩個正整數n和p,表示選手的個數以及精度要求。接下來的n行,每行包含乙個0到100 閉區間 內的整數。output 輸出乙個實數,取p位有效數字,下取整。sample input 5 4 100 20 15 10 8 sample output 195.2 data constr...