hdu 5694 BD String (遞推)

http://acm.hdu.edu.cn/showproblem.php?pid=5694

衆所周知,度度熊喜歡的字符只有兩個:B和D。 

今天,它發明了一種用B和D組成字符串的規則: 

S(1)=BS(1)=B 

S(2)=BBDS(2)=BBD 

S(3)=BBDBBDDS(3)=BBDBBDD 

… 

S(n)=S(n−1)+B+reverse(flip(S(n−1))S(n)=S(n−1)+B+reverse(flip(S(n−1)) 

其中,reverse(s)reverse(s)指將字符串翻轉,比如reverse(BBD)=DBBreverse(BBD)=DBB,flip(s)flip(s)指將字符串中的BB替換爲DD,DD替換爲BB,比如flip(BBD)=DDBflip(BBD)=DDB。 

雖然度度熊平常只用它的電腦玩連連看,這絲毫不妨礙這臺機器無與倫比的運算速度,目前它已經算出了S(21000)S(21000)的內容,但度度熊畢竟只是只熊,一次讀不完這麼長的字符串。它現在想知道,這個字符串的第LL位(從1開始)到第RR位,含有的BB的個數是多少? 
 

Input

第一行一個整數TT,表示T(1≤T≤1000)T(1≤T≤1000) 組數據。 

每組數據包含兩個數LL和R(1≤L≤R≤1018)R(1≤L≤R≤1018) 。 

Output

對於每組數據,輸出S(21000)S(21000)表示的字符串的第LL位到第RR位中BB的個數。

Sample Input

3
1 3
1 7
4 8

Sample Output

2
4
3

首先用a[i] 存儲第i個字符串的長度, 因爲l ,r 小於10^18, 所以只需要開到a[60] 就可以了 (2^60 > 10^18)

get(x) 求 1 ~ x中B的個數

舉個例子:

第一個紅框中B的個數爲c, 第二個爲a, 第三個爲b;

如果我要求箭頭處(x)的前綴的B的個數 sum = c + a + 1 + b

因爲取反再反轉,所以 a和b是互補的, 所以 a 和 b 中 B 的個數 等於 len(a), 也就是a的長度

而 len(a) = x - a[3] - 1 , 加上中間的一個B,可以抵消 - 1

c中B的個數就用遞歸求

所以 get(x) =  get(a[i] - x )  +  (x - a[i]  - 1 ) + 1  ==  x - a[i-1] + get(a[i] - x);

#include <bits/stdc++.h>
using namespace std;
using lon = long long;

lon a[65];

lon get(lon x)
{
	if(x == 0) return 0;
	
	for(int i = 1; i <= 60; i++)
	{
		if(a[i] == x)
			return x / 2 + 1;
		
		if(x < a[i])
			return x - a[i-1] + get(a[i] - x);
	}
}

int main()
{
	for(int i = 1; i <= 60; i++)
	a[i] = a[i-1] * 2 + 1;
	
	int T;
	cin >> T;
	while(T--)
	{
		lon l, r;
		cin >> l >> r;
	//	cout << get(l-1) << endl;
		cout << get(r) - get(l-1) << endl;
	}
	
	return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章