小木棍加强版解题报告
【题目描述】:
简易描述:
给定 \(n(n\leq 65)\)个数值(每一段不超过\(50\)),输出其能够拼成的最小木棒长度;
也就是只有看过题面的人才看的懂。
具体描述 : QwQ
【杂言】:
看到最小值, 由于上两天刷了二分和三分,这个题,我觉得可以用二分,我不会,\(so\ , \ pass\)
我看了一下有一个查看题解,我立马,打开我的小蓝本,我错了,我大大的错了,我是真不知道小蓝本的解法错误,我的时间随着小蓝本在我手中揉捏而逝去1个半小时,气死我了,但是小蓝本的分析和题意解读的挺不错的。
为了写这一篇,博客我分别把哪一步优化去掉,能得多少分,还去看了一下
【思路分析】:
提供其他解法了
我们发现有种朴素的做法,那就是我们可以从小到大枚举每一种的长度出现的情况,反正必然是个整数,然后呢,搜索,看一下是否可以用我们现有的木棒拼出来,复杂度大概是\(O(n\times 2^n),\)期望得分,20分,我觉得行,好歹有点分。
考虑对其进行优化:
1.输入的时候扔掉\(length≥50\),题目中提供的
2.我们枚举可能出现的长度是从最大值枚举一直枚举到\(\sum \limits_{i = 1 } ^ n \ len_{i}\) , 其中显然包括了出现的所有情况
3.在进行操作的时候,长木棍肯定是比几根能够拼成同样长度的小木棒要死板一下,所有取小木棒也就是更灵活一些,让短小的能够自由组合,我们枚举小木棒的时候,从大到小枚举
4.原长度是一定可以被总长度整除的,我一开始就是考虑删除50以上的会不会对答案进行干扰,放心,这里一点都不会进行干扰,
5.在进行搜索的时候,我们从上一次搜索的继续,这里选用的是桶,因为数据不是很多的样子,而且可以省去既要记录小木棒长度,又要其编号
6.搜索判断一下搜到的几根木棒是否会大于,那也就没必要搜下去了,返回。
7.木棒原来的长度是一定大于等于所剩下的木棒中,最长的那一根
8.在进行搜索的时候, 如果在搜索的上一次是 0 , 那么意味着根本没法拼
9.如果正常搜索的时候 , \(i\ + \ last \ == len\),但是由于\(now\) 的限制,无法通过,让其返回即可,没必要在进行操作了
注 : 若未进行第优化 8 , 9 。只能得到 54 分的高分, 只有优化 8 , 54分, 只有优化 9 , 78分的高分。
【Code】:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
#define inf 0x3f
#define QwQ printf("运行过了") ;
using namespace std ;
inline int read()
{
int x = 0 , f = 1 ; char ch = getchar() ;
while(!isdigit(ch)){ if(ch =='-') f = - 1 ; ch = getchar() ; }
while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar() ; }
return x * f ;
}
int n , cnt , tot , maxn , flag , m ,ans , len , minn;
int num[70];
void prepare()
{
n = read() ;
for(int i = 1 ; i <= n ; i++)
{
int length = read() ;
if(length > 50) continue ;
else
{
num[length]++ ;
tot += length ;
maxn = max(maxn , length ) ;
minn = min(minn , length ) ;
}
}
}
bool search(int now , int former , int last )
{
if(now == cnt + 1 ) // 搜索一直不出问题,自然 OK
{
return true ;
}
if(former == len)
{
return search(now + 1 , 0 , maxn ) ;
}
for(int i = last ; i >= minn ; i--)
{
if(i + former <= len && num[i] ) //棍子相加不能超过限制, 并且这棍子还有
{
num[i] -- ;
if(search(now , i + former , i))
{
return true ;
}
num[i] ++ ;//回溯
if(former == 0 || former + i == len)
{
return false ;
}
}
}
return false ;
}
signed main()
{
prepare() ;
for(len = maxn ; len <= tot ; len ++)
{
if(tot % len == 0)
{
cnt = tot / len ;
if(search(1 , 0 , maxn ) )
{
ans = len ;
}
}
}
printf("%d" , ans ) ;
return 0 ;
}