給定乙個區間[l,r],問l到r的整數中有幾個轉換成二進位制數後0比1多(不計前導零)。
例如對於整數11,它二進位制拆分後是1011
1011
1011
按照上述過程進行拆分能得到多個不同的二進位制數:
1010(10
)1010(10)
1010(1
0), 1000(8
)1000(8)
1000(8
) , 0000(0
)0000(0)
0000(0
)它們互相組合,可以得到整個區間:
[
0000
,1000
)[0000,1000)
[0000,
1000
),[1000
,1010
)[1000,1010)
[1000,
1010
)以及1011
可以發現這樣就可以把1−n
1-n1−
n之間的數全都包含,這樣就可以用類似字首和的形式求出答案:
w or
k(r+
1)−w
ork(
l)
work(r+1)-work(l)
work(r
+1)−
work
(l)其中r+1
r+1r+
1,ll
l是因為work求的是比work()中的數小的數,是因為我們沒有把最後那個落單的整數算上去,只算到了[1,
n−1]
[1,n-1]
[1,n−1
]區間。
我們將二進位制處理出來之後,我們就可以列舉每一位,如果當前位是0,那麼就把0的總數加1,否則就將答案累加。
我們預處理出組合數cij
c_i^j
cij
表示在i個可以選的位置中插入j個0的合法方案數
設二進位制長度為len
而上述過程計算的是長度等於len的方案數。
由於這裡是計算[1,
n−1]
[1,n-1]
[1,n−1
]之間所有的方案數,所以我們還要計算長度小於len的方案數。
雙重迴圈累加即可,過程與上述相似。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
int l,r,len =0;
int c[
6060][
6060];
int a[
1010100];
void
init()
//預處理組合數
voidcl(
int x)
}//二進位制拆分處理
intwork
(int x)
signed
main()
}
//ps:tm的不知道為什麼,這題開long long會炸,大家千萬不能開long long!!! 組合數學 求組合數
對於求組合數,要根據所給資料範圍來選擇合適的演算法 這道題中所給的資料範圍適合用打表的方法直接暴力求解 先用4e6的複雜度預處理出所有的情況,再用1e4的複雜度完成詢問即可 include using namespace std const int n 2010 const int mod 1e9 ...
數學 組合數學
mod must be a prime const int mod 1e9 7 namespace combinatory ll inv ll x ll fac maxn invfac maxn void initc int n ll a ll n,ll m ll c ll n,ll m ll d ...
組合數學筆記
從n個數中選m個數,每個數至多選一次,方案數 性質 c n,0 c n,n 1 c n,m c n,n m c n,m c n 1,m 1 c n 1,m 楊輝三角 二項式展開 x y n i 0.n c n,i x iy n i 那這裡先說一下楊輝三角 前提 每行端點與結尾的數為1 每個數等於它上...