Family

题目

Sarila负责为今年信息组的聚会制作蛋糕,她买了n个蛋糕,第i个蛋糕长度为 ai,宽度为bi,高度为1(这里长宽是可以互换的)。Sarila想组合出一个最大的长方体蛋糕塔,蛋糕塔每层的蛋糕尺寸是一样的。她决定从某一些蛋糕里切出一个x*y的子矩形,再把这些x*y的矩形蛋糕叠起来作为蛋糕塔。一块蛋糕只能切出一块x*y的子矩形,剩余部分不能继续使用,且必须沿着平行与长宽方向切割。
现在她想请你帮忙,对于每一个蛋糕塔的高度h,确定x,y使得每一层蛋糕的面积尽量大。
对于100%的数据,1<=n<=3000,1<=ai,bi<=10^8

题意

即确定最大的x*y,然后满足的(a>=x)and(b>=y)的个数为h便是第h层的最大值,请你求出1到h的最大x*y

分析

很明显这题允许我们用 O(n2) 的算法去做,那么我们便可以去考虑了。
因为ai,bi<= 108 ,故我们可以用离散化解决ai太大的问题。
首先这题有很多种做法,我只讲我的方法,不喜勿喷,也欢迎互相讨论
我们接着分析,发现每个x,y一定时某一个ai或bj(请读者想一想)
我们先排序ai,bi,双关键字(从大到小)
那么我们便可以先枚举一个i,以ai为x。
然后我们可以把只要满足ak>=ai的bk统计一下,然后我们会发现这里是线性的(因为是从大到小,那么这个值一定也能被下一个ai+1用到,因为ai+1<=ai)
那么我们只用统计一下所有ak=ai的bk即可(这是 O(n)
用桶来处理(h[i]表示bk为i的满足的个数)
我们再枚举一下j(离散的值),这时我们便知道满足:(ai<=ak)and(bi<=bk)的值,即桶里面的值。
然后用ai*bj的值去更新an[h[j],1]*an[h[j],2]的值(an[h[j],1..2]表示的是满足h[j]组数满足的最大的乘积的两个数)

代码比较丑,用了类似前缀和来处理(因为比赛没太多时间去思考。。)
用类似前缀和原因还有一个是:我是一块一块处理(相同的ai以前处理)
故用其来处理

var
    x:array[0..10005,1..2] of longint;
    a:array[0..10005,1..3] of longint;
    i,nu,num,j,k,n:longint;
    an:array[0..10000,1..2] of int64;
    b,c,d:array[0..10000] of int64;
procedure qsort(l,r:longint);
var i,j,mid,mie:longint;
begin
     i:=l;j:=r;mid:=x[(l+r)shr 1,1];mie:=x[(l+r)shr 1,2];
     repeat
         while (x[i,1]>mid)or((x[i,1]=mid)and(x[i,2]>mie)) do inc(i);
         while (x[j,1]<mid)or((x[j,1]=mid)and(x[j,2]<mie)) do dec(j);
         if i<=j then begin
            x[0]:=x[i];x[i]:=x[j];x[j]:=x[0];inc(i);dec(j);
         end;
     until i>j;
     if l<j then qsort(l,j);
     if i<r then qsort(i,r);
end;
procedure qso(l,r:longint);
var i,j,mid:longint;
begin
    i:=l;j:=r;mid:=a[(l+r)shr 1,1];
    repeat
        while a[i,1]<mid do inc(i);
        while a[j,1]>mid do dec(j);
        if i<=j then begin
           a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];inc(i);dec(j);
        end;
    until i>j;
    if l<j then qso(l,j);
    if i<r then qso(i,r);
end;
procedure swap(var x,y:longint);
var t:longint;
begin t:=x;x:=y;y:=t;end;
begin
assign(input,'family.in');reset(input);
assign(output,'family.out');rewrite(output);
    readln(n);
    for i:=1 to n do begin
        readln(x[i,1],x[i,2]);
        if x[i,1]<x[i,2] then swap(x[i,1],x[i,2]);
    end;
    qsort(1,n);
    for i:=1 to n do begin
        inc(nu);a[nu,1]:=x[i,1];a[nu,2]:=i;a[nu,3]:=1;
        inc(nu);a[nu,1]:=x[i,2];a[nu,2]:=i;a[nu,3]:=2;
    end;
    qso(1,nu);
    a[0,1]:=0;
    for i:=1 to nu do begin
        if a[i,1]<>a[i-1,1] then begin inc(num);b[num]:=a[i,1];end;
        x[a[i,2],a[i,3]]:=num;
    end;
    x[0,1]:=0;i:=1;
    while i<=n do begin
         inc(d[1]);dec(d[x[i,2]+1]);
         for j:=i+1 to n do
         if x[j,1]=x[j-1,1] then begin inc(d[1]);dec(d[x[j,2]+1]);end else break;
         for k:=1 to num do d[k]:=d[k-1]+d[k];
         for k:=1 to num do begin c[k]:=c[k]+d[k];d[k-1]:=0;end;d[num]:=0;
         if x[j,1]<>x[j-1,1] then dec(j);
         for k:=1 to num do
         if b[an[c[k],1]]*b[an[c[k],2]]<b[k]*b[x[i,1]] then begin an[c[k],1]:=k;an[c[k],2]:=x[i,1];end;
         i:=j+1;
    end;
    for i:=n downto 1 do begin
        for j:=i+1 to n do
        if b[an[i,1]]*b[an[i,2]]<b[an[j,1]]*b[an[j,2]] then an[i]:=an[j];
    end;
    for i:=1 to n do writeln(b[an[i,1]],' ',b[an[i,2]]);
    close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值