Description
在幻想乡,雾雨魔理沙是住在魔法之森普通的黑魔法少女。话说最近魔理沙从香霖堂拿到了升级过后的的迷你八卦炉,她迫不及待地希望试试八卦炉的威力。在一个二维平面上有许多毛玉(一种飞行生物,可以视为点),每个毛玉具有两个属性,分值value和倍率mul。八卦炉发射出的魔法炮是一条无限长的直线形区域,可以视为两条倾斜角为α的平行线之间的区域,平行线之间的距离可以为任意值,如下图所示:
蓝色部分上下两条长边之间就是这次八卦炉的攻击范围,在蓝色范围内的毛玉(红点)属于该此被击中的毛玉,如果一个毛玉刚好在边界上也视为被击中。毛玉击中以后就会消失,每次发射八卦炉得到分值是该次击中毛玉的分值和乘上这些毛玉平均的倍率,设该次击中的毛玉集合为S,则分值计算公式为:
Score = SUM{value[i] | i 属于 S} * SUM{mul[i] | i 属于 S} / |S|
其中|S|表示S的元素个数。魔理沙将会使用若干次八卦炉,直到把所有毛玉全部击中。任意两次攻击的范围均不重叠。最后得到的分值为每次攻击分值之和。现在请你计算出能够得到的最大分值。
Input
第1行:1个整数N,表示毛玉个数
第2..N+1行:每行四个整数x, y, value, mul,表示星星的坐标(x,y),以及value和mul
第N+2行:1个整数α,表示倾斜角角度,0°到180°
Output
第1行:1个实数,表示最大分值,保留三位小数
Hint
[数据范围]
对于60%的数据:1 <= N <= 500
对于100%的数据:1 <= N <= 2,000
-10,000 <= x,y <= 10,000
1 <= value,mul <= 100
[注意]
π = 3.1415926
题解
无力吐槽题目背景:-D
不懂得斜率和三角函数于是悲剧了(>﹏<)
过每个点作与x轴成α°的直线,求得与y轴的交点坐标,相同的点缩成一个作dp就好了
c++和pascal自带tan()函数,手动提到某位用计算器的同学
代码
#include <algorithm>
#include <stdio.h>
#include <cmath>
#define p 3.1415926
using namespace std;
struct maoyu
{
double x,y,value,mul;
};
maoyu a[10001],w[10001];
int g[10001],yy[10001];
double d[10001],t;
int cnt=0;
bool cmp(maoyu x,maoyu y)
{
return x.x<y.x;
}
int find(double v)
{
for (int i=1;i<=cnt;i++)
if (abs(w[i].x-v)<=0.00001)
return i;
return 0;
}
int main()
{
int n,arc;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int aa,ab,ac,ad;
scanf("%d%d%d%d",&aa,&ab,&ac,&ad);
a[i]=(maoyu){aa,ab,ac,ad};
}
scanf("%d",&arc);
t=tan((double)(arc)*p/180.0);
for (int i=1;i<=n;i++)
{
double f=a[i].y-a[i].x*t;
int tmp=find(f);
if (tmp)
{
yy[tmp]++;
w[yy[tmp]].value*=a[i].value;
w[yy[tmp]].mul*=a[i].mul;
}
else
{
w[++cnt].x=f;
w[cnt].value=a[i].value;
w[cnt].mul=a[i].mul;
yy[cnt]++;
}
}
sort(w+1,w+cnt+1,cmp);
double ans=0;
for (int i=1;i<=cnt;i++)
{
double val=0,mui=0,st=0;
for (int j=i;j<=cnt;j++)
{
st+=yy[j];
val+=w[j].value;
mui+=w[j].mul;
d[j]=max(d[j],d[i-1]+mui*val/st);
ans=max(d[j],ans);
}
}
printf("%.3f\n",ans);
return 0;
}