bzoj 4870 組合數問題

2022-06-03 08:42:10 字數 1123 閱讀 4472

目錄求:

\[\sum_^c_^\mod p

\]原題傳送門。

這不是單位根反演裸題嗎

注意到模數並沒有特殊性質,可以想到從組合數的遞推公式入手。

當 k = 1 實際上就是快速冪,所以聯想到說不定可以矩陣冪優化。

記 \(f_n(r) = \sum_^c_^\),則:

\[f_n(r) = \sum_^c_^\times f_(r - j \mod k)

\]從組合意義上不難理解上面的式子。

那麼就可以構造矩陣 a 使得 \(a_ = c_^ + [i - j = 0 \mod k]\),跑個 \(o(k^3\log n)\) 的矩陣加速。

雖然這道題資料範圍看上去好像可以過,不過還有更快的優化方法。

注意到 a 是乙個迴圈矩陣,即 \(a_ = g(i - j \mod k)\)。同時可以證明 a 的冪也一定是迴圈矩陣。

因此,只需要維護 a 對應的 g 就可以還原出 a,而 g 的維護是 \(o(k^2)\) 的卷積,因此總時間複雜度降為 \(o(k^2\log n)\)。

如果你覺得上述演算法不好理解,事實上對於本題還有另一種理解方式:

\[f_(r) = \sum_^f_a(j)\times f_b(r - j \mod k)

\]一樣地,從組合意義不難理解上式。

也就是 dp 狀態之間可以作 「復合」 運算。那麼直接對 dp 做倍增,然後把需要的 2 的冪 「復合」 起來即可。

嘛,不過這種理解方法和上面那個是等價的就是了。

#include #include int n, p, k, r;

inline int add(int x, int y)

inline int mul(int x, int y)

int t[55];

void merge(int *a, int *b, int *c)

for(int i=0;i>=1,merge(f, f, f))

if( i & 1 ) merge(f, g, g);

}int c[55][55];

int main()

for(int i=0;i事實上,這種思路還可以延伸到 \(a_ = g(i - j*a)\) 之類的情況,不過和上面的略有些不同就是了。

Bzoj4870 SHOI2017 組合數問題

題目顯得一臉不可做。一般的來說,讀題是不會看前面一些沒有什麼太大意義的話的。確實也如此,譬如題面首句 組合數cm n 表示的是從n個互不相同的物品中選出m個的方案數 想來大家也是知道的 再觀察前面的式子 可以表示成如下形式 q modk rcq n k 回顧題面首句 代入?可以得到講人話的題面,大致...

BZOJ 4870 HEOI 2017 組合數問題

第一行有四個整數 n,p,k,r,所有整數含義見問題描述。1 n 10 9,0 r k 50,2 p 2 30 1 一行乙個整數代表答案。我也是很迷呢,這題如果用組合數公式 性質硬搞什麼也搞不出來,然後就用組合數的實際意義好了,c i,j 表示從i個物品中選出j個的方案數,那麼原題就是從n k個物品...

BZOJ 4870 HEOI2017 組合數問題

題面 time limit 10 sec memory limit 512 mb submit 484 solved 242 submit status discuss 第一行有四個整數 n,p,k,r,所有整數含義見問題描述。1 n 10 9,0 r k 50,2 p 2 30 1 一行乙個整數代...