scauoj_11158 切水果

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值