题目传送门
题意: 本来有一些长度相同的小木棍,我们把它们切成了若干个长度不一定相同的小木棍,且这些小木棍长度均不大于50(输入时需要手动过滤),问你原来木棍的最小可能的长度是多少?
思路: 显然原来的长度一定是合法小木棍长度和的因子,并且这个因子要大于小木棍中的最大值。我们计算总和之后枚举因子,因为要输出最小的因子,所以我们正向枚举。每次遇到因子就搜索,搜索的时候需要注意的剪枝策略:
1、如果这次的搜索是符合条件的可以直接输出答案然后退出程序。
2、如果上次搜索的木棍长度是p,下一层搜索就从p开始,从大到小枚举小木棍。
3、如果此时已拼接的木棍长度是0 或者 已拼接的长度加上目前这根刚好等于需要的长度但是并没有退出程序,应该直接退出这层函数,因为继续向下找不会有更多的选择了。
代码:
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
//#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;}
using namespace std;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-7;
const double PI=acos(-1);
int tem[110],cnt=0,maxn=0,minn=100,tot=0;
void dfs(int num,int sum,int len,int p)
{
if(num==0)
{
cout<<len<<endl;
exit(0);
}
if(sum==len)
{
dfs(num-1,0,len,maxn);
return ;
}
for(int i=p;i>=minn;i--)
{
if(tem[i]&&sum+i<=len)
{
tem[i]--;
dfs(num,sum+i,len,i);
tem[i]++;
if(sum==0||sum+i==len)
return ;
}
}
}
signed main()
{
int n;
cin>>n;
int t;
while(n--)
{
cin>>t;
if(t<=50)
{
cnt++;
tem[t]++;
tot+=t;
maxn=max(maxn,t);
minn=min(minn,t);
}
}
for(int i=maxn;i<=tot;i++)
{
if(tot%i==0)
{
dfs(tot/i,0,i,maxn);
}
}
}