JZOJ 2555【NOIP2011模拟9.7】雾雨魔理沙 几何计算&动态规划

来源:互联网 发布:淘宝运作流程图 编辑:程序博客网 时间:2024/06/05 17:32

这道题是本人在训练中发现的,具有挺高的教学意义,因此做一下分析。

简化一下题目大意,是这样的:在一个二维平面上给出若干个点,你可以划出一个无限宽,但是与X轴的夹角为Alpha度的区间,此区间的收益为区间所覆盖的点的(分数和*倍数和/点数),求最大的收益和。(区间不能重叠)
这里写图片描述

乍一看,似乎无从下手,甚至想出了按斜率排序的处理。但是,仔细看一下,发现:如果从每个点出发做一条直线,且直线同时交X轴Alpha度,就能得到一个交点,如果选取的区间的边界覆盖了这个交点,不就刚好能被选到了吗?

于是乎,新的想法出炉了:
这里写图片描述
但是,新的问题又来了!怎么求落在X轴上的点呢?
我们都知道一次函数的公式:(Y=KX+B)
我们有点(x1,y1)和点(0,y2),Y=K*X1+B,0=K*X2+B, 移项得:
-B=K*X2,X2=-B/K! 也就是说,只要得出BK,就能得出落在X轴上点的位置。K可以用正切函数得到,K=Tan(Alpha*π/180)B也就等于(Y-K*X1)。很轻松地得出X2

求出落点后,判断下有没有落点重复的,合并(一个落点必须同时选或不选)。再进行DP就完成了。

CODE(由于楼主很懒,没有时间翻译成C,所以只贴上一段P)

uses math;var        x,y:array[1..2000]of longint;        value,mul,sum1,sum2:array[0..2000]of longint;        i,j,l,n,m,a,last:longint; k,b:real;        poi:array[0..2000]of real;        f:array[0..2000]of real;        bz:array[1..2000]of boolean;procedure sort(l,r:longint);var        i,j:longint; mid:real;begin        i:=l;j:=r;        mid:=poi[(i+j) div 2];        repeat                while poi[i]<mid do inc(i);                while poi[j]>mid do dec(j);                if i<=j then                begin                        value[0]:=value[i];value[i]:=value[j];value[j]:=value[0];                        poi[0]:=poi[i];poi[i]:=poi[j];poi[j]:=poi[0];                        mul[0]:=mul[i];mul[i]:=mul[j];mul[j]:=mul[0];                        inc(i);dec(j);                end;        until i>j;        if i<r then sort(i,r);        if j>l then sort(l,j);end;begin        readln(n);        for i:=1 to n do                readln(x[i],y[i],value[i],mul[i]);        readln(a);        k:=tan(a*3.1415926/180);        for i:=1 to n do        begin                b:=y[i]-k*x[i];                poi[i]:=b;        end;        sort(1,n);        last:=1;        for i:=2 to n do        begin                if (poi[i]=poi[last]) then                begin                        inc(value[last],value[i]);                        inc(mul[last],mul[i]);                        value[i]:=0;                        mul[i]:=0;                        bz[i]:=true;                end else                        last:=i;        end;        sum1[1]:=value[1];        sum2[1]:=mul[1];        for i:=2 to n do        begin                sum1[i]:=sum1[i-1]+value[i];                sum2[i]:=sum2[i-1]+mul[i];        end;        for i:=1 to n do        for j:=1 to i do                f[i]:=max(f[i],f[j-1]+(sum1[i]-sum1[j-1])*(sum2[i]-sum2[j-1])/(i-j+1));        writeln(f[n]:0:3);end.

Thanks For Watching.

2 0
原创粉丝点击