JZOJ(C组)雾雨魔理沙

    xiaoxiao2025-05-23  4

    题目:在幻想乡,雾雨魔理沙是住在魔法之森普通的黑魔法少女。话说最近魔理沙从香霖堂拿到了升级过后的的迷你八卦炉,她迫不及待地希望试试八卦炉的威力。在一个二维平面上有许多毛玉(一种飞行生物,可以视为点),每个毛玉具有两个属性,分值value和倍率mul。八卦炉发射出的魔法炮是一条无限长的直线形区域,可以视为两条倾斜角为α的平行线之间的区域,平行线之间的距离可以为任意值,如下图所示:      蓝色部分上下两条长边之间就是这次八卦炉的攻击范围,在蓝色范围内的毛玉(红点)属于该此被击中的毛玉,如果一个毛玉刚好在边界上也视为被击中。毛玉击中以后就会消失,每次发射八卦炉得到分值是该次击中毛玉的分值和乘上这些毛玉平均的倍率,设该次击中的毛玉集合为S,则分值计算公式为:   Score = SUM{value[i] | i 属于 S} * SUM{mul[i] | i 属于 S} / |S|

      其中|S|表示S的元素个数。魔理沙将会使用若干次八卦炉,直到把所有毛玉全部击中。任意两次攻击的范围均不重叠。最后得到的分值为每次攻击分值之和。现在请你计算出能够得到的最大分值。

    分析:这道题目像一次函数,用tan(α)就可表示Y=KX+B中的K值了(具体用数学演算,找到函数与X坐标轴交点后再在函数上任意找一点来推断就可以了。)再用DP,状态转移方程:f[i]:=max(f[i],f[j]+(sum1[i]-sum1[j])*(sum2[i]-sum2[j])/(sum[i]-sum[j]));

    附上代码:

    uses math; const   maxn=3000; var   x,y,value,mul,sum,sum1,sum2:array [0..maxn] of longint;   f,compare:array [0..maxn] of double;   flag:array [0..maxn] of boolean;   n,angle,times:longint;   real1:double; procedure init; var   i:longint; begin   readln(n);   for i:=1 to n do     readln(x[i],y[i],value[i],mul[i]);   readln(angle);   real1:=tan(angle*pi/180);   for i:=1 to n do     compare[i]:=y[i]-real1*x[i]; end; procedure qsort(l,r:longint); var   i,j,temp:longint;   test,mid:double; begin   i:=l;   j:=r;   mid:=compare[(i+j) div 2];   repeat     while compare[i]<mid do       inc(i);     while compare[j]>mid do       dec(j);     if i<=j then       begin         test:=compare[i];         compare[i]:=compare[j];         compare[j]:=test;         temp:=x[i];         x[i]:=x[j];         x[j]:=temp;         temp:=value[i];         value[i]:=value[j];         value[j]:=temp;         temp:=y[i];         y[i]:=y[j];         y[j]:=temp;         temp:=mul[i];         mul[i]:=mul[j];         mul[j]:=temp;         inc(i);dec(j);     end;   until i>j;   if i<r then     qsort(i,r);   if l<j then     qsort(l,j); end; function max(a,b:double):double; begin   if a>b then     exit(a);   exit(b); end; procedure prepare; var   i,j:longint; begin   qsort(1,n);   for i:=1 to n do     if not flag[i] then       begin         flag[i]:=true;         inc(times);         inc(sum[times]);         sum1[times]:=sum1[times]+value[i];         sum2[times]:=sum2[times]+mul[i];         for j:=i+1 to n do           if not flag[j] then             begin               if compare[j]=compare[i] then                 begin                   flag[j]:=true;                   inc(sum[times]);                   sum1[times]:=sum1[times]+value[j];                   sum2[times]:=sum2[times]+mul[j];                 end;             end;      end; end; procedure main; var   i,j:longint; begin   for i:=2 to times do     begin       sum[i]:=sum[i]+sum[i-1];       sum1[i]:=sum1[i]+sum1[i-1];       sum2[i]:=sum2[i]+sum2[i-1];     end;   for i:=1 to times do     for j:=0 to i-1 do       f[i]:=max(f[i],f[j]+(sum1[i]-sum1[j])*(sum2[i]-sum2[j])/(sum[i]-sum[j]));   writeln(f[times]:0:3); end; begin   init;   prepare;   main; end.

    转载请注明原文地址: https://ju.6miu.com/read-1299178.html
    最新回复(0)