對於給定的數字\(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種顏色的花瓣數為奇數,他想知道,有多少種選擇方案能有這樣...