自主命題 奇組合數個數統計

2022-06-17 08:30:15 字數 3143 閱讀 7430

對於給定的數字\(n,l,r\),求在 \(c_n^l,c_n^,c_n^,\dots,c_n^r\) 中共有多少個奇數。

行號\(n\)從0開始計數。特別地,我們規定\(c_0^0 = 1\)。

資料保證 \(0 \leq n \leq 10^\)

拿到乙個1e18的題,第一反應肯定是先打個表看看嘛。

我們知道有楊輝三角:

\[1\\

1 \ \ \ 1\\

1 \ \ \ 2 \ \ \ 1\\

1 \ \ \ 3 \ \ \ 3 \ \ \ 1\\

1 \ \ \ 4 \ \ \ 6 \ \ \ 4 \ \ \ 1\\

1 \ \ \ 5 \ \ \ 10 \ \ \ 10 \ \ \ 5 \ \ \ 1\\

1 \ \ \ 6 \ \ \ 15 \ \ \ 20 \ \ \ 15 \ \ \ 6 \ \ \ 1 \\

1 \ \ \ 7 \ \ \ 21 \ \ \ 35 \ \ \ 35 \ \ \ 21 \ \ \ 7 \ \ \ 1 \\

\dots \ \ \ \ \ \ \ \dots \ \ \ \ \ \ \ \dots

\]我們把其中的奇數標成1,偶數標成0,於是得到:

\[1\\

1 \ \ \ 1\\

1 \ \ \ 0 \ \ \ 1\\

1 \ \ \ 1 \ \ \ 1 \ \ \ 1\\

1 \ \ \ 0 \ \ \ 0 \ \ \ 0 \ \ \ 1\\

1 \ \ \ 1 \ \ \ 0 \ \ \ 0 \ \ \ 1 \ \ \ 1\\

1 \ \ \ 0 \ \ \ 1 \ \ \ 0 \ \ \ 1 \ \ \ 0 \ \ \ 1 \\

1 \ \ \ 1 \ \ \ 1 \ \ \ 1 \ \ \ 1 \ \ \ 1 \ \ \ 1 \ \ \ 1 \\

\dots \ \ \ \ \ \ \ \dots \ \ \ \ \ \ \ \dots

\]你也可以再列出一些,不過總之我們發現,這個01構成的三角形似乎有著某種絕佳的對稱性。

實際上,這正是一種分形,名叫謝爾賓斯基三角形。

根據這種絕佳的對稱性,我們容易設計出一種分治演算法:

typedef long long ll;

ll solve(ll n, ll l, ll r)

return ret;

}

我們用cnt_0統計所求行最中間0的個數,

r表示將中間的0去掉後左側部分的右端點,

l表示將中間的0去掉後右側部分的左端點。

然後分別向左右兩側遞迴地計算答案。

這種寫法比較直觀,但不是最優美簡潔的。

該演算法的複雜度分析是比較困難的,不過我們容易發現 \(n = 2 ^ t - 1\) 時是最壞的情況。

此時有 \(t(n) = 2 \times t(\frac) + log_2 n\),複雜度是略大於\(o(n)\)的。

但經測試,在資料隨機的背景下,\(n\) 在 1e11 的量級時該演算法仍然有較好的表現。

平均複雜度的證明留給讀者。

求奇偶性,不就是求 \(mod\ 2\) 的值嗎?

求組合數取模後的結果,不就是lucas定理嗎?

此外,利用上面的切爾賓斯基三角形其實也是證明lucas定理的一種方法。

lucas's theorem:

\[\binom \equiv \binom \cdot \binom \ \ \ \ (mod \ \ p)

\]其中,

\[\binom = c_n^m

\]只是另一種表達方式罷了,只不過這樣寫更容易看清。

接下來我們考慮求 \(c_n^m \ mod \ 2\),可以考慮對 \(c_n^m\) 連續使用lucas定理。

我們將\(n, m\)兩個數二進位制表示:

\[n = \sum_^k a_i \cdot 2^i \\

m = \sum_^k b_i \cdot 2^i

\]這裡 \(n,m\) 的二進位制位數當然不一定相同,我們可以在最高位補0,效果相同。

那麼我們有,

\[\binom \equiv \prod _ ^ k \binom \ \ \ \ (mod \ p)

\]如果 \(c_n^m\) 是奇數,那麼右式就應當為得1,否則即為0。

而我們知道\(a_i, b_i\)的取值只有\(0, 1\),又有:

\[\binom00 = 1,\ \binom01 = 1,\ \binom11 = 1,\ \binom10 = 0

\]稍作觀察就能發現:

\[\binom \ mod \ 2 = \cases

\]由此,我們 \(o(n)\) 地列舉 \([l, r]\) 間的所有整數即可。

register long long cnt = 0;

for(register long long i = l; i <= r; ++i)

cnt += ((i | n) == n);

**就這。

可以發現我們用了一下lucas定理之後平均複雜度可能還不如找規律。

這是因為我們列舉了 \([l, r]\) 間的所有整數的緣故。

但考慮現在的問題:求 \([l, r]\) 間或\(n\)得\(n\)的數的個數,這是乙個容易解決的數字dp問題。

#includeusing namespace std;

typedef long long ll;

vectorlim;

ll n, l, r, dp[64][2];

int len;

ll dfs(int ith, bool ful)

else

}else res += dfs(ith + 1, ful & (!lim[ith]));

return dp[ith][ful] = res;

}ll solve(ll x)

len = lim.size();

reverse(lim.begin(), lim.end());

return dfs(0, true);

}int main()

複雜度是易於分析的\(o(logn)\),證明留給讀者。

小奇的賞花(數學排列組合)

題目描述 小奇的花園裡有n行m列棵桃花樹,花色各不相同。小奇漫步在花園中,有時它覺得某一行 列的桃花很美,便會在這一整行 列的每棵樹下撿一枚花瓣,到了傍晚,他發現自己選擇了r行c列 同一行 列可能被選擇不止一次 的花瓣。回家之後,小奇發現 有s種顏色的花瓣數為奇數,他想知道,有多少種選擇方案能有這樣...