简化一下题目大意,是这样的:在一个二维平面上给出若干个点,你可以划出一个无限宽,但是与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! 也就是说,只要得出B和K,就能得出落在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.