小木棍
题目传送门:https://www.luogu.org/problemnew/show/P1120
题解:不存在的
直接上代码,看注释请慎重,因为我也不知道我的注释对不对
#include<cstdio> #include<algorithm> using namespace std; int n,a[70],minx,maxn,d,cnt,len,nxt[70],m; bool vis[70],flag; bool cmp(int x,int y){return x > y;} void dfs(int k,int last,int res) {//k表示当前木棍编号,last为正在拼的木棍的前一节编号,res为还需长度 int i; if(!res)//还需长度为0,证明拼完了 { if(k == m)//m根木棍都拼好了 { flag = true; return; } for(i = 1;i <= cnt;i++)//找到一个还没用过的木棍 if(!vis[i]) break; vis[i] = true; dfs(k+1,i,len-a[i]);//用它拼接 vis[i] = false; if(flag) return;///找到答案层层退出 } int l = last + 1,r = cnt,mid; while(l < r)//二分查找下一次拼接的木棍,该木棍是不大于所需长度的第一根木棍 { mid = (l+r)>>1; if(a[mid] <= res) r = mid; else l = mid+1; } for(i = l;i <= cnt;i++)//由于所有木棍是按从大到小的顺序排的,因此从上述找到的木棍向右枚举 { if(!vis[i]) { vis[i] = true; dfs(k,i,res-a[i]); vis[i] = false; if(flag) return; if(res == a[i] || res == len) return; //当前正在拼长棍剩余的未拼长度等于当前小木棍的长度,说明它只能自组,但继续拼下去却失败,说明它不能自组。 //当前木棍剩余的未拼长度等于原始长度,说明这根原来的长棍还一点没拼。还需要继续拼接,但继续拼下去却失败 ,所以无法用上它。 //flag = 0 继续拼下去失败 i = nxt[i]; if(i == cnt) return; } } } int main() { scanf("%d",&n); for(int i = 1;i <= n;i++) { scanf("%d",&d); if(d <= 50) { a[++cnt] = d; minx = max(minx,a[cnt]);//上限 maxn += a[cnt];//上限 } } sort(a+1,a+cnt+1,cmp); nxt[cnt] = cnt; for(int i = cnt - 1;i > 0;i--) { if(a[i] == a[i+1]) nxt[i] = nxt[i+1]; else nxt[i] = i; } for(len = minx;len <= maxn/2;len++)//i为枚举的长度 { if(maxn%len==0)//若长度恰能被总长度整除,则这个长度是合法的 { m = maxn/len;//原先有m根木棍 flag = 0; vis[1] = 1; dfs(1,1,len-a[1]); vis[1] = 0; if(flag) { printf("%d\n",len); return 0; } } } printf("%d\n",maxn); return 0; }