87,TLE on 30……玄关!
查看原帖
87,TLE on 30……玄关!
222431
Atlantic_C929楼主2025/7/1 20:35

用尽一切力气和手段,差6ms过不去。TAT

自认为有保姆级注释,并且已知的剪枝都用了……

求还有没有剪枝……

#include<bits/stdc++.h>
using namespace std;
int n,totlen,maxlen,aim,vis[70],a[70];//totlen总长,maxlen最长的一根,aim目标每一段的长度,vis是否被用过,n和a是输入
int cmp(int x,int y)//从大到小排
{
	return x>y;
}
//快读快写
int in(){
	int k=0,flag=1;
	char c=getchar_unlocked();
	while(c<'0' || c>'9') {
		if(c=='-') flag=-1;
		c=getchar_unlocked(); }
	while(c>='0' && c<='9') {k=k*10+c-'0';c=getchar_unlocked();}
	return k*flag;
}
int out(int x){
	if(x<0){putchar('-');x=-x;}
	if(x>=10){out(x/10);putchar(x%10+'0');}
	else{putchar(x+'0');}
	return 0;
}
int dfs(int now,int sum,int used,int last)//now是拼到第几根,sum是已经拼了多长,used是用了几根,last是上一根拼上去的多长(下一根一定不比它长)
{
	if(sum==aim)//一段拼完,下一段
		return dfs(now+1,0,used,0);
	if(used==n)//所有木棒都用完
	{
		if(sum==0)//这个看起来好像不可能不等于0……?
			return 1;
		else
			return 0;
	}
	int k=0;//详见后第5行
	for(int i=last+1;i<=n;i++)
	{
		if(vis[i]==1)//用过了,直接下一个
			continue;
		if(k>0 && a[i]==a[k])//和上一次尝试但是失败的一样长,直接跳过
			continue;
		if(sum+a[i]<=aim)//这段拼上去不超过长度
		{
			vis[i]=1;//标记已使用
			int tmp=dfs(now,sum+a[i],used+1,i);
			vis[i]=0;//退掉标记
			if(tmp==1)//有可行的方案
			{
				return 1;
			}
			else//没有可行的方案
			{
				if(sum==0 || sum+a[i]==aim)//这是第一段/最后一段,直接不要。(就是一个剪枝)
					return 0;
				k=i;//不可行的记下来(上面那个if剪枝)
			}
		}
	}
	return 0;
}
int main()
{
	n=in();
	for(int i=1;i<=n;i++)
	{
		a[i]=in();
		totlen+=a[i];
		maxlen=max(maxlen,a[i]);
	}
	sort(a+1,a+n+1,cmp);//排序剪枝
	for(aim=maxlen;aim<totlen;aim++)//最短是最长的一段,最长是总长
	{
		if(totlen%aim!=0)//无法拼成整数段,直接不要
			continue;
		int tmp=dfs(1,0,0,0);//1是可行,0是不可行
		if(tmp)//有了可行的方案
		{
			out(aim);
			return 0;
		}
	}
	out(totlen);//只能全部拼成一段
	return 0;
}
2025/7/1 20:35
加载中...