题目描述
纸条终于传到了Z的手上。这个秘密是什么呢?
原来D发现了一些小纸片,这些纵向长度不一,横向长度都为1个单位长度的小纸片是从一张地图上剪下来的,由于地图有磨损,D无法通过纸片上的图案将完整的地图拼出来,所以她向Z求助。
经过Z的分析,这张地图是一个完整的矩形,并且它的长宽是一定的。Z确信一旦长宽确定,她就能把地图拼出来。
现在,D分析出绘制这张地图的人会用横向尽可能长,纵向尽可能窄的短卷式纸张。她向你求助,希望知道这张地图的横向和纵向长度(其中横向长度尽可能长,纵向长度尽可能短)。
输入
共2行。
第1行,一个整数n,表示纸片数量(1≤n≤60)。
第2行,n个整数,表示各张纸片的纵向长度(1≤l≤50)。
输出
共2行。
第1行,一个整数表示地图的横向长度。
第2行,一个整数表示地图的纵向长度。
题解
题目实际上是要求我们把给定数字分成和相同的几组,组数尽量多
直接上dfs会TLE
剪枝:
- 因为一定是矩形,所以只需要枚纸条长度和的约数
- 题目要求最大,那么找到第一个就可以退了
- 只需要判断是否存在
然而一坨优化比不上媳妇随手的cpp
Code
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
int num[61],l[61],n,x=0,sum=0;
bool flag;
bool cmp(int a,int b)
{
return a>b;
}
void dfs(int now,int dep,int lim)
{
if (now>lim||flag)
return;
if (dep>n)
{
for (int i=1;i<now;i++)
if (l[i]!=sum/lim)
return;
x=sum/lim;
flag=true;
return;
}
for (int i=1;i<=now;i++)
if (l[i]+num[dep]<=sum/lim)
{
l[i]+=num[dep];
dfs(now,dep+1,lim);
l[i]-=num[dep];
}
l[now+1]=num[dep];
dfs(now+1,dep+1,lim);
l[now+1]=0;
}
int main()
{
freopen("map.in","r",stdin);
freopen("map.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
sum+=num[i];
}
sort(num+1,num+n+1,cmp);
for (int mid=(int)sqrt(sum);mid>=1;mid--)
if (sum/mid*mid==sum)
{
flag=false;
dfs(1,1,mid);
if (flag)
break;
}
printf("%d\n%d\n",sum/x,x);
return 0;
}