小木棍

 

题目传送门: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;
}

 

posted @ 2018-10-29 16:54  我的露娜不会飘  阅读(158)  评论(0编辑  收藏  举报