題解:CF633D Fibonacci-ish

zla_2012發表於2024-10-25

涉及知識點:列舉,STL

題目大意

給你一個序列,讓你選出一些元素,使其構成 fibonacccccci 數列,求數列的最大長度。

解題思路

定義一個桶,$mp_i$ 代表 $i$ 這個數在輸入序列當中出現的次數。

由於 $n \le 1000$,所以可以直接暴力列舉 fibonacccccci 數列的前兩個數。

前兩個數固定了,這個序列的所有數字都固定了,只需要判斷當前序列的下一個數字可不可以組合出來。

map<int, int> hh;
int cnt = 2;
int now1 = a[i];
int now2 = a[j];
hh[now1]++, hh[now2]++;
while (hh[now1 + now2] < mp[now1 + now2]) {
  int t = now1;
  now1 = now2;
  now2 = t + now2;
  hh[now2]++;
  cnt++;
}

再來說一下剪枝。

  1. 如果序列裡包含 $0$,先把 $ans$ 初始化成 $0$ 的個數,這樣就可以防止列舉起點的多餘計算。
  2. 如果序列包含兩個及以上個 $0$,需要在列舉前兩個數時特判,因為起始兩個 $0$ 的序列全是 $0$,會在第 $1$ 種剪枝當中直接計算出來最優解。
  3. 如果前一個序列的第 $1$ 個數和這個序列的第 $1$ 個數相同,說明兩個序列是完全一樣的,直接跳過當前序列,計算下一個序列。

最後,統計每個序列長度,取最大值即可。

程式碼

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define il inline
using namespace std;

const int N = 1000 + 10;

int n, a[N];
map<int, int> mp;
int ans;
vector<int> v;

il void Init() {
	cin >> n;
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
}

il void Solve() {
	for (int i = 1; i <= n; i ++ ) mp[a[i]]++;//統計數字出現個數
	ans = max(ans, mp[0]);//剪枝1
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; i ++ )
		for (int j = 1; j <= n; j ++ ) {
			if (i == j) continue;//起始不能為同一個位置的數
			if (a[i] == 0 && a[j] == 0) continue;//剪枝2
			if (i > 1 && a[i - 1] == a[i]) break;//剪枝3
			map<int, int> hh;//統計當前序列數字出現的個數
			int cnt = 2;
			int now1 = a[i];
			int now2 = a[j];
			hh[now1]++, hh[now2]++;
			while (hh[now1 + now2] < mp[now1 + now2]) {
				int t = now1;
				now1 = now2;
				now2 = t + now2;
				hh[now2]++;
				cnt++;//統計當前序列長度
			}
			ans = max(ans, cnt);//更新答案
		}
	cout << ans;
}

signed main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
//	freopen("fibonacci.in", "r", stdin);
//	freopen("fibonacci.out", "w", stdout);
	int T = 1;
//	cin >> T;
	while (T--) {
		Init();
		Solve();
	}
}

透過記錄