11158 切水果
时间限制:1000MS 内存限制:65535K
提交次数:638 通过次数:82
题型: 编程题 语言: G++;GCC
Description
Lrc是校队里面的总所周知的全才王,他不仅是一个excelent acmer,也不仅是一个chess master,更是一个crazy game player。 切水果,正是他最喜欢玩的手机游戏之一。为了避免有人没玩过,下面介绍一下Lrc是怎么玩这个游戏的~-~ 1) 整个屏幕是一个笛卡尔坐标系。 2) 在某个时刻,屏幕上会出现灰常多的水果,西瓜、草莓神马的,当然还有一种,炸弹。 3) 每个时刻用手指在屏幕上划过,切中水果可以得到一定得分数,切到炸弹就要扣分。 4) 每个时刻最多只能切一刀,至于一刀切多少个可以自由控制。 5) 第t时刻没有被切的水果,将不会出现在下一个时刻。 6) 由于Lrc 骨骼奇精,所以手指在屏幕上只能划线段,也就是说只有在同一线段上的水果他才能在同一时间内切到。(友情提醒,线段不仅是斜的,也可以是水平和垂直的哦)。 由于Lrc比较神,每次他总能得到最高分。嘿嘿,你想要成为未来的Acmer吗?那就必须帮Lrc算出他的分数咯O(∩_∩)O~ ---------------------------------------------------------------------------------------------------------------------------------------- PS:记住,Acmer要有永不言弃的精神,花一天过了这个题,值得了~~~~~ 还有,输出的句子,请直接复制题目上面的,不要手打,以防出错!!! (出题人Ly)
输入格式
第一行3个整数n(n<=150),m(m<=20),k(0=<k<=1e9+7),分别代表这一局出现的水果(炸弹)数,水果种类,以及每切中一个炸弹要扣的分数。 紧接着一行m个整数v1,v2,v3….vm(0<=vi<=10000),分别代表m种水果的分数。 接下来n行分别代表一个水果(炸弹),每行4个整数x,y,p,t(x,y代表该水果的坐标,p代表该水果得种类(p=0时为炸弹),t代表该水果出现的时刻)(-1000<=x,y<=1000,0<=p<=m,0<=t<=90)。
输出格式
若Lrc 得到的分数不大于零,请输出“Poor Lrc!!!”,因为他将要受到强神的BS; 否则,输出“God Lrc, you’ve got S points!”,S是Lrc得到的分数。
输入样例
sample#1: 1 1 10 10 0 0 1 1 sample#2: 6 3 20 1 2 10 0 1 2 1 100 100 2 2 0 2 0 1 0 3 3 1 1 1 3 2 0 0 1 1
输出样例
sample#1: God Lrc, you’ve got 10 points! sample#2: God Lrc, you’ve got 22 points!
提示
样例中的sample#1,sample#2不属于输入输出的一部分,只是说明其不是一个输入和输出。Attention: 炸弹当一个水果就行了!!切到炸弹不结束!!
来源
Ly作者
scau_acm
题解:直接模拟啦。。把相同时间的归在一起,再把同一线段的放在一起,求最大子段和(dp)就可以了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <stack>
using namespace std;
typedef struct boom
{
int x,y,p,t;
}boom;
boom w[200],q[200];
int fruit[200],ans;
map<double,int> flag1,flag2;
stack<int> r;
bool cmp(boom a,boom b)
{
if(a.t<b.t)
return true;
else if(a.t==b.t)
{
if(a.x<b.x)
return true;
else if(a.x==b.x)
{
if(a.y<b.y)
return true;
else
return false;
}
else
return false;
}
else
return false;
}
void solve(int n)
{
int k=w[1].t,len=0;
w[n+1].t=-100;
for(int i=1;i<=n;i++)
{
if(w[i].t==k)
{
q[++len]=w[i];//出现时间相同
}
if(w[i+1].t!=k)//不相同
{
int maxend=0;
//printf("当前的时刻为%d\n\n",k);
for(int j=1;j<=len;j++)
{
for(int l=j;l<=len;l++)
{
double u=(q[j].y-q[l].y);
if(q[j].x-q[l].x!=0)//斜率存在
{
u=1.0*u/(q[j].x-q[l].x);//斜率
if(flag1.find(u)==flag1.end())//该斜率的没算过
{
r.push(q[j].p);
if(j!=l)
r.push(q[l].p);//j,l水果进栈
flag1[u]=1;
int s=0;
for(int m=l+1;m<=len;m++)//讲这一时刻所有斜率为u的进栈
{
if(q[m].x!=q[j].x)
{
double u0=1.0*(q[m].y-q[j].y)/(q[m].x-q[j].x);
if(fabs(u0-u)<1e-9)
{
r.push(q[m].p);
}
}
}
//求最大子段和
while(!r.empty())
{
int v=r.top();
r.pop();
if(s>0)
s+=fruit[v];
else
s=fruit[v];
maxend=max(maxend,s);
}
}
}
else//斜率不存在
{
double u=1.0*q[j].x;
if(flag2.find(u)==flag2.end())
{
flag2[u]=1;
r.push(q[j].p);
if(j!=l)
r.push(q[l].p);
int s=0;
for(int m=l+1;m<=len;m++)
{
if(q[m].x==q[j].x)
{
r.push(q[m].p);
}
}
//求最大字段和
while(!r.empty())
{
int v=r.top();
r.pop();
if(s>0)
s+=fruit[v];
else
s=fruit[v];
maxend=max(maxend,s);
}
}
}
}
}
ans+=maxend;
flag1.clear();
flag2.clear();
len=0;
k=w[i+1].t;
//printf("获得了%d分数\n",maxend);
}
}
}
int main()
{
int n,m,k;
cin>>n>>m>>k;
fruit[0]=-k;
for(int i=1;i<=m;i++)
cin>>fruit[i];
for(int i=1;i<=n;i++)
cin>>w[i].x>>w[i].y>>w[i].p>>w[i].t;
sort(w+1,w+1+n,cmp);
solve(n);
if(ans>0)
printf("God Lrc, you’ve got %d points!\n",ans);
else
printf("Poor Lrc!!!\n");
return 0;
}