题解:P1120 小木棍

很简单的搜索题,我的做法暴搜加剪枝,时间复杂度也就 \(O(n!\ m)\) 而已……

  • 首先,理清思路,要求原始木棍的最小可能长度。

设答案为 \(ans\),最长的木棍长 \(len\),长度总和为 \(sum\)。那么 \(ans \in [len,sum]\),这是必然的。

那么不妨从最大的木棍长度一直搜索到所有木棍的总和,如果长度可以,那么直接输出答案。

虽然保证了 \(a_i \le 50\),但保险起见,我们用一个桶来记录数量。

  • 然后,考虑如何设计 dfs 的状态。

由于我们是从最大的木棍长度一直搜索到所有木棍的总和,所以首先必然要有 当前可以使用的最长木棍的长度 \(len\)需要得到的木棍的长度 \(need\)

到底几根呢?所以还要有 还需要拼凑得到的木棍数量 \(res\) 以及 当前已经拼凑得到的木棍的长度 \(l\)

  • 最后,考虑如何解决。
  1. 边界条件是拼完了,即 \(res = 0\)
  2. 如果当前拼凑出的木棍的长度等于需要得到的木棍的长度,则开始拼凑下一根。
  3. 直接从最大往最小暴力,判断是否可行,即小木棍数量是否大于 0,且当前木棍长度 \(i + l <= need\)

Code

#include <bits/stdc++.h>
#define qwq(i,a,b) for(int i=(a);i<=(b);++i)
#define qaq(i,a,b) for(int i=(a);i>=(b);--i)

using namespace std;

typedef long long ll;

const int N = 70;

int sum = 0;
int n, cnt;
int a[N];
int mx, mn;

/*
如何设计 dfs?
考虑一下。。。。。。。。。

已知:要拼木棍。

可以这样设计:
还需要拼凑得到的木棍数量、
当前已经拼凑得到的木棍的长度、
需要得到的木棍的长度、
当前可以使用的最长木棍的长度。

那么直接搞。
*/
inline void dfs(int res, int l, int need, int len) {
    // cout << res << ' ' << l << ' ' << need << ' ' << len << '\n';
	if (res == 0) {
		cout << need;
		exit(0);
	}
	
	// 如果当前拼凑出的木棍的长度等于需要得到的木棍的长度,则开始拼凑下一根
	if (l == need) {
		dfs(res - 1, 0, need, mx);
	}
	
	// 直接从最大往最小暴力
	qaq (i, len, mn) {
		// 如果可行,即小木棍数量 > 0,且当前木棍长度 i + l <= need
		if (a[i] && i + l <= need) {
			a[i]--; // 用一根木棍
			dfs(res, l + i, need, i);
			a[i]++;
			if (l == 0 || i + l == need) return ;
		}
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> n;
	
	qwq (i, 1, n) {
		int x;
		cin >> x;
		if (x > 50) continue;
		a[x]++;
		cnt++;
		sum += x;
        mx = max(mx, x);
        mn = min(mn, x);
	}
	
	/*
	答案必然 >= 最长的木棍,那么不妨从最大的木棍长度一直搜索到所有木棍的总和,如果长度可以,那么直接输出答案。
	*/
	
	qwq (i, mx, sum >> 1) {
		if (sum % i != 0) continue; // 优化 1:因为拼成的长度相等,所以显然有一个数 x,可以整除所有的木棍长度,那么不能整除的直接 continue
		else {
			dfs(sum / i, 0, i, mx);
		}
	}
	
	cout << sum;
}
posted @ 2025-06-26 12:35  swate  阅读(27)  评论(0)    收藏  举报
body{ cursor: url(https://files.cnblogs.com/files/wkfvawl/cursor.ico),auto; }