# Recursion# Dynamic Programming# String# Binary Search

f508 - 12041 - BFS (Binary Fibonacci String)

🔗 前往 ZeroJudge 原題

題目描述

題目定義了一個二進位制的費波那契字串 BFS,其中 BFS(0) = "0",BFS(1) = "1",BFS(n) = BFS(n-2) + BFS(n-1)。題目要求輸出 BFS(N) 字串中從第 L 個字元到第 R 個字元(包含 L 和 R)的子字串。

解題思路

這題的核心在於高效地計算 BFS(N) 的第 k 個字元,而不需要實際生成整個字串。程式碼使用遞迴的方式來模擬 BFS 的生成過程,並根據 k 的值來決定遞迴到哪一個子問題。

首先,預先計算出費波那契數列,用於確定每個 BFS(n) 的長度。在 dp 函數中,如果 n 大於 69,則使用 n = 68 - n % 2 來避免整數溢位,因為 BFS(n) 的長度會快速增長。

遞迴過程中,根據 k 的大小,判斷它落在 BFS(n-2) 還是 BFS(n-1) 中。如果 k 小於或等於 BFS(n-2) 的長度,則遞迴計算 BFS(n-2) 的第 k 個字元。否則,遞迴計算 BFS(n-1) 的第 (k - BFS(n-2)) 個字元。

在主函數中,對於每個測試案例,程式碼遍歷從 L 到 R 的每個位置 i,並使用 dp 函數計算 BFS(N) 的第 i+1 個字元,然後輸出該字元。

複雜度分析

  • 時間複雜度: O(R-L+1) * O(N),其中 N 是輸入的數字,R 和 L 是查詢的範圍。每次查詢需要遞迴調用 dp 函數,最壞情況下遞迴深度為 N。
  • 空間複雜度: O(N),主要用於儲存費波那契數列和遞迴調用堆疊。

程式碼

#include <iostream>
using namespace std;
long long int fib[70]={0,1},ac,g;
void dp(long long int n,long long int k){
	if(n==1&&k==1){
		cout << "0";
		g=1;
		return;
	}
	else if(n==2&&k==1){
		cout << "1";
		return;
	}
	if(n>69)n=68-n%2;
	long long int size=fib[n];
	if(k>size){
		ac=0;
		return;
	}
	if(n%2){
		long long int xs=fib[n-2];
		if(k<=xs){
			dp(n-2,k);
		}
		else{
			dp(n-1,k-xs);
		}
	}
	else{
		long long int y1s=fib[n-2],xs=fib[n-3];
		if(k<=y1s){
			dp(n-2,k);
		}
		else if(k<=y1s+xs){
			dp(n-3,k-y1s);
		}
		else{
			dp(n-2,k-y1s-xs);
		}
	}
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	for(int i=2;i<70;++i){
		fib[i]=fib[i-1]+fib[i-2];
	}
	long long int m,n,l,r;
	cin >> m;
	while(m--){
		ac=1;
		cin >> n >> l >> r;
		++n;
		g=0;
		for(int i=l;i<=r&&ac;++i){
			if(g==1){
				cout << '1';
				g=0;
			}
			else{
				dp(n,i+1);
			}
		}
		cout << "\n";
	}
}

Discussion