暴搜的思路并不难想到,主要难点是各种优化、各种剪枝:

预先处理出所有木棍的总长度,且保证枚举答案的值能被总长度整除。

每根木棍的长度可用桶来存储,并且预先处理出最长的和最短的木棍的长度,搜索时从最大长度到最小长度递减枚举。

若拼接当前木棍时已用了一根长为X的木棍,则dfs时从长度X开始搜索。

若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案 时,则可直接跳出循环,因为此时继续枚举其它更小的值时,显然可能情况更少,且同样凑不完。

注意常数不要太大。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,nn[70],sum=0,mid2=0,mii=0,md,flag=0,mxx,mnn=2e9;
int cnt=0,x;
/*
nn数组表示当前长度的木棍的个数 sum表示全部木棍长度 

mid2表示原本有多少根木棍
*/
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a>b?b:a;}
void checkdfs(int ss,int sm,int p){//(一共有多少根大木棍,和为多少,从长度为多少的木棍开始搜索)
    if(ss==0){printf("%d",md);exit(0);}
    if(sm==md){checkdfs(ss-1,0,mxx);return;}
    for(int i=p;i>=mnn;i--){
        if(nn[i]&&(i+sm<=md)){
            nn[i]--;
            checkdfs(ss,sm+i,i);
            nn[i]++;
            if(sm==0||sm+i==md)break;
            }
    }
    return;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(x>50)continue;
        nn[x]++;
        cnt++;
        sum+=x;
        mxx=max(mxx,x);
        mnn=min(mnn,x);
    }
     //mii=sum;
     for(int i=cnt;i>=2;i--){//从 初始化棍数最多 开始找  因为棍数越多,每根长度越小
         if(sum%i==0){
             mid2=i;
             md=sum/i;
             //printf("mid2:%d\n md:%d",mid2,md);
             //flag=0;
             checkdfs(mid2,0,mxx);
             //if(flag){mii=min(mii,md);}
         }
     }
     /*for(int i=mxx;i<=sum>>1;i++){
         if(sum%i==0){
             md=i;
             flag=0;
             checkdfs(sum/i,0,i,50);
             //if(flag)mii=min(mii,i);
         }
     }*/
     printf("%d",sum);//最后都没输出,则输出 所有小木棒的总和
    return 0;
}