題目大意:
給n個數,求在n個數中選兩個數(可重複),使得這兩個數的組合數是奇數,求總共有多少種取法。
解題思路:
組合數cn
m奇偶性判斷:
n & m == m 成立則組合數為奇數
一開始沒什麼的思路,直接暴力超時,後來看到lucas定理,發現上面那個式子的本質就是從這裡推導出來的。
lucas定理:
組合數判斷奇數的話就是轉化成上述定理中p = 2
是否為1,利用lucas定理,先把
和化為二進位制,這樣它們都是01序列了。我們又知道
。這樣中為0的地方對應的
中的位置只有一種可能,那就是0。
這樣n&m = m的本質就是二進位制中n對應的0得地方,m也對應為0。
然而,就是這個本質,就可以解這道題目
有位大佬一句話點醒了我,n&m = m說明m是n的子集。
對的,用二進位制表示子集的時候,就是這樣,m是n的子集,等價於n為0的位置m一定為0,n為1
的位置,m可以為1,可以為0。
然後對於每個n,求出它的子集的數目即可。
對於求子集,大佬教的方法是高維字首和,**很簡單,就三行,和狀態壓縮dp一樣。
1舉個例子,sum[0101] = sum[0101] + sum[0100] + sum[0001] + sum[0000]for(int i = 0; i < m; i++)
28 }
sum[i]就表示i二進位制的所有子集的權值之和
對於組合數n & m == m m是n的子集,
先統計每個數出現的次數,然後對於每個數,統計它的子集的個數即可,最後答案相加。
1 #include2using
namespace
std;
3const
int maxn = 1e6 + 10
;4 typedef long
long
ll;5
ll a[maxn], sum[maxn];
6int
main()720
int m = 17;21
for(int i = 0; i < m; i++)
2228
}29 ll ans = 0;30
for(int i = 0; i < n; i++)
31 ans +=sum[a[i]];
32 cout
34return0;
35 }
SSL ZYC 奇數統計
題目大意 給出n個正整數,其中只有乙個數出現了奇數次,其餘的數都出現偶數次。求那個出現了奇數次的數。思路 直接暴力!下面給出兩種做法 1 不保險的 桶排 2 保險的 快排 這道題個人認為快拍更加保險。因為題目沒有告訴你這個數字最大是多少,使用桶排有可能會爆記憶體。雖然這道題用快排比桶排慢,但是更加保...
1547 奇數統計(count)
題目描述 給出n個正整數,其中只有乙個數出現了奇數次,其餘的數都出現偶數次。求那個出現了奇數次的數。1 n 500000,n肯定是奇數。所有出現數都不超過10000。輸入 第一行是n,下一行有n個正整數。輸出 出現了奇數次的數。樣例輸入 樣例輸入1 931 22171 3173 樣例輸入2 5 12...
EOJ2846 統計字串個數
在 0 和 1 組成的長度為 的字串中,輸出不包含 101 子串的字串的個數。本題有多組測試資料。每組測試資料佔一行,含乙個正整數 表示字串的長度。n 1 表示輸入結束。對每組測試資料,在一行中輸出表示不包含 101 子串的字串的個數。如果結尾為0,那麼不包含101的有d n 1 個 如果結尾為1,...