# Dynamic Programming# String# Greedy# Recursion

e984 - 連假時在做什麼?有沒有空?可以來打code嗎?

🔗 前往 ZeroJudge 原題

題目描述

題目要求找出第 K 個 Lunlun Number。Lunlun Number 的定義是,其十進位表示中,每一位數字與前一位和後一位數字的差值不超過 1。

解題思路

這題使用動態規劃 (DP) 的概念,透過遞迴建表來產生 Lunlun Number。程式碼從 "1" 和 "0" 開始,逐步產生更大的 Lunlun Number。dp 函數遞迴地生成下一個 Lunlun Number,並將其儲存在 ans 陣列中。 核心邏輯是,如果當前數字串的所有位數都是 '9',則在末尾添加 '1' 並將其他位數設為 '0'。否則,從最高位開始,嘗試將某一位數字加 1,並根據加 1 的結果調整後續位數,以確保滿足 Lunlun Number 的條件。

複雜度分析

  • 時間複雜度: O(K * L),其中 K 是輸入的數字,L 是 Lunlun Number 的最大長度。因為需要生成 K 個 Lunlun Number,且生成每個 Lunlun Number 的時間複雜度與其長度成正比。
  • 空間複雜度: O(K * L),因為需要儲存 K 個 Lunlun Number,每個 Lunlun Number 的長度最長為 L。

程式碼

#include <iostream>
using namespace std;
int k;
string ans[10002]={"0","1"};
void dp(int al,int now){
	if(now==10001)return;
	bool add=1;
	for(int i=0;i<al;++i){
		if(ans[now][i]!='9'){
			add=0;
		}
	}
	if(add==1){
		++now;
		ans[now]+="1";
		for(int i=0;i<al;++i)
			ans[now]+='0';
		dp(al+1,now);
		return;
	}
	else{
		for(int i=al-1;i>0;--i){
			if(ans[now][i]+1<='9'&&abs(ans[now][i]+1-ans[now][i-1])<=1){
				ans[now+1]=ans[now];
				ans[now+1][i]++;
				for(int j=i;j<al;++j)
					if(ans[now+1][j]>'0')
						ans[now+1][j+1]=ans[now+1][j]-1;
					else
						ans[now+1][j+1]='0';
				dp(al,now+1);
				return;
			}
		}
		ans[now+1]=ans[now];
		ans[now+1][0]++;
		for(int i=0;i<al;++i)
			if(ans[now+1][i]>'0')
				ans[now+1][i+1]=ans[now+1][i]-1;
			else
				ans[now+1][i+1]='0';
		dp(al,now+1);
		return;
	}
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	dp(1,1);
	while(cin >> k)
		cout << ans[k] << "\n";
}

Discussion