Description
在时间的流逝中一切都不断改变着,当我意识到这一点时,已经无法再前进了。
Sarila在高中时参加了信息学竞赛。信息组就像一个大家庭,即便分开,羁绊仍然是存在的,这就是所谓的同学吧。
Sarila负责为今年信息组的聚会制作蛋糕,她买了n个蛋糕,第i个蛋糕长度为 ai,宽度为bi,高度为1(这里长宽是可以互换的)。Sarila想组合出一个最大的长方体蛋糕塔,蛋糕塔每层的蛋糕尺寸是一样的。她决定从某一些蛋糕里切出一个xy的子矩形,再把这些xy的矩形蛋糕叠起来作为蛋糕塔。一块蛋糕只能切出一块x*y的子矩形,剩余部分不能继续使用,且必须沿着平行与长宽方向切割。
现在她想请你帮忙,对于每一个蛋糕塔的高度h,确定x,y使得每一层蛋糕的面积尽量大。
Input
第一行一个整数n。
接下来n行每行两个整数ai,bi 。
Output
输出n行,第i行两个整数表示当蛋糕塔的层数h=i时,使得x*y最大的x,y 。
若有多组可行的x,y ,输出任意一组即可。
Sample Input
3
2 4
4 2
3 3
Sample Output
3 3
2 4
3 2
Data Constraint
对于30%的数据,n<=10,ai,bi<=15
对于50%的数据,n<=200,ai,bi<=400
对于70%的数据,n<=2500,ai,bi<=3000
对于100%的数据,1<=n<=3000,1<=ai,bi<=10^8
赛时
0
正解
考虑反一个方向来做,通过数字来找边,对于每个蛋糕x,y(x<y),则f[x][y]++,之后做一个二维后缀和,那么此时的f[x][y]就表示选x,y为两个边时最多可以选f[x][y]个蛋糕,所以这时就可以统计答案了,然后有一点,我们可以用x,y来更新n比f[x][y]小的情况,因为假设我的x,y能选10个,那么9个,8个也能选,所以是不断更新的。
然后看的出这样打就70分,但是要知道可以离散化
码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 3007
using namespace std;
int n,f[2*N][2*N],b[2*N],maxx,maxy;
long long ansx[N],ansy[N],rt[2*N];
struct node{
int x,y;
}a[N];
int main(){
freopen("family.in","r",stdin);
freopen("family.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].x>a[i].y)
swap(a[i].x,a[i].y);
b[i*2-1]=a[i].x;
b[i*2]=a[i].y;
}
sort(b+1,b+2*n+1);
int cnt=unique(b+1,b+2*n+1)-b-1;
for(int i=1;i<=n;i++){
int x,y;
x=lower_bound(b+1,b+cnt+1,a[i].x)-b;
y=lower_bound(b+1,b+cnt+1,a[i].y)-b;
rt[x]=a[i].x;
rt[y]=a[i].y;
f[x][y]++;
maxx=max(maxx,x);
maxy=max(maxy,y);
}//以上是输入和离散化
for(int i=maxx;i>=1;i--)
for(int j=maxy;j>=1;j--){
f[i][j]=f[i+1][j]+f[i][j+1]-f[i+1][j+1]+f[i][j];//二维后缀和
}
for(int i=1;i<=maxx;i++)
for(int j=1;j<=maxy;j++)
if(ansx[f[i][j]]*ansy[f[i][j]]<rt[i]*rt[j])
ansx[f[i][j]]=rt[i],ansy[f[i][j]]=rt[j];//统计答案
for(int i=n-1;i>=1;i--)
if(ansx[i]*ansy[i]<ansx[i+1]*ansy[i+1])
ansx[i]=ansx[i+1],ansy[i]=ansy[i+1];//用x,y来更新n比f[x][y]小的情况
for(int i=1;i<=n;i++)
printf("%d %d\n",ansx[i],ansy[i]);
}