2020河南省CCPC 我得重新集结部队

这是一个关于《星际争霸II》的模拟问题,描述了狂热者与异虫的战斗过程。题目中给出了每个单位的属性,包括攻击力、攻击范围和生命值,并详细说明了攻击规则。在一系列事件后,需要判断每个单位的状态,即狂热者是否离开战场,异虫是否死亡。解题关键在于理解战斗规则和处理精度问题,通过模拟战斗过程得出最终结果。
摘要由CSDN通过智能技术生成

时间限制: 1 Sec  内存限制: 128 MB

题目描述

为了保护科普卢星区的和平,大主教阿塔尼斯每时每刻都在指挥部队抗击肆虐的虫群。最近,阿塔尼斯把目光投向了又一颗布满虫群的星球。在这次行动中,阿塔尼斯计划使用狂热者铲除星球上的虫群威胁。
狂热者是星灵的基本近战兵种,每个狂热者有一个攻击力 atk 和一个攻击范围 r。在狂热者发动攻击时,他会冲向距离最近的异虫,在这只异虫处释放 3 次威力强大的旋风斩。若有多只距离最近的异虫,他会选择最早出现的那只。若当前没有存活的异虫,那么这只狂热者会在原地释放旋风斩。每次旋风斩会对所有与攻击者距离小于等于 r 的异虫进行攻击,对每只异虫造成 atk 的伤害(生命值减少 atk)。
当然,这些异虫也是不好惹的。每只异虫具有初始生命值 h,当生命值小于等于 0 时,该异虫将会死亡(并离开战场)。但是,在一次攻击中,若一只异虫受到 3 次旋风斩后仍未死亡,那么它将会对进攻的狂热者进行反击,使这个狂热者不得不离开战场。
在整个战役中,按照时间顺序依次发生了 n 个事件,事件有以下两种:

  1. 异虫出现。一只初始生命值为 h 的异虫单位出现在  (x,y)坐标。
  2. 折跃狂热者。一个狂热者被折跃到了  (x,y) 坐标,冲向距离最近的异虫(若存在)并发动 3 次旋风斩。若此后该狂热者没有受到反击,那么他将会一直留在战场,但是不会继续进行攻击。

你作为阿塔尼斯的副官,想知道战场的最终情况:每个狂热者是否离开了战场,以及每只异虫是否死亡。

输入

第一行包含一个整数 n (1≤n≤2×103),代表事件的数量。
接下来 n 行,每行给出一种事件,格式为以下两种之一:
    1 x y h,代表一个生命值为 h 的异虫出现在了坐标 (x,y)。
    2 x y atk r,代表一个攻击力为 atk,攻击半径为 r 的狂热者被折跃到了坐标  (x,y),并立即进行攻击。
上述所有的x,y,r 均为整数,满足  0≤∣x∣,∣y∣,r≤108;所有的 atk,h 均为整数,满足 1≤atk,h≤108。

输出

输出 n 行,第 i 行表示第 i 个事件中出现的异虫或狂热者最终是否留在战场。Yes 表示异虫未死亡或狂热者未离开战场,No 表示异虫死亡或狂热者离开战场,大小写不敏感。

样例输入 Copy

5
1 0 0 4
1 0 1 8
2 1 0 1 1
2 1 0 1 1
2 1 0 1 1

样例输出 Copy

No
No
No
No
Yes

提示

在样例中,发生了如下事件:

  1. 事件 1 中,在 (0,0)处出现了一只异虫,其生命值为 4。
  2. 事件 2 中,在 (0,1)处新出现了一只异虫,其生命值为 8。
  3. 事件 3 中,在  (1,0)  处折跃一只攻击力为 1,攻击半径为 1 的狂热者,他移动到坐标 (0,0) 后,发动 3 次旋风斩。异虫 1,2 分别剩余生命值 1,5,随后狂热者受到反击离开战场。
  4. 事件 4 中,在 (1,0)  处折跃一只攻击力为 1,攻击半径为 1 的狂热者,他移动到坐标 (0,0) 后,发动 3 次旋风斩。异虫 1 死亡,异虫 2 剩余生命值 2,随后狂热者受到反击离开战场。
  5. 事件 5 中,在  (1,0)  处折跃一只攻击力为 1,攻击半径为 1 的狂热者,他移动到坐标 (0,1) 后,发动 3 次旋风斩。异虫 2 死亡,狂热者留在战场。

因而,最终所有异虫死亡,只有狂热者 5 留在战场。

做的时候真的是WA麻了,没有考虑到double精度如何处理,哭死。

解题思路:

本题是一个模拟题,按题意实现即可,复杂度为 O ( n 2 ) 。需要注意以下
几个点:
1. 出现多只与狂热者距离相同的异虫时,需要选取最早出现的那只。
2. 考虑狂热者距离时不能考虑已经死亡(离开战场)的异虫。
3. 距离平方的极限数据可达 4 × 10 ^16 ,使用 double 计算有可能会产生浮点
精度误差。但是注意到距离之间只需要比较大小,因而可将所有距离平
方,在长整型范围内进行运算,避免精度误差。

AC代码:

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
#define int long long
struct ss
{
    int x,y,r;
    int hp;
    int k;
    bool g;
} p[2020];
 
int dist(int x1,int x2,int y1,int y2)
{
    return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
 
signed main()
{
    int n;
    cin>>n;
 
    for(int i=1; i<=n; i++)
    {
        cin>>p[i].k>>p[i].x>>p[i].y>>p[i].hp;
        if(p[i].k==2)
            cin>>p[i].r;
    }
 
    for(int i=1; i<=n; i++)
    {
        if(p[i].k==2)
        {
            int dis=1e18+7;
            int h=-1;
 
            for(int j=1; j<i; j++)
            {
                if(p[j].hp<=0||p[j].k==2)
                    continue;
                int s=dist(p[i].x,p[j].x,p[i].y,p[j].y);
                if(s<dis)
                {
                    dis=s;
                    h=j;
                }
            }
 
            if(h!=-1)
                for(int j=1; j<i; j++)
                {
                    if(p[j].hp<=0||p[j].k==2)
                        continue;
                    dis=dist(p[h].x,p[j].x,p[h].y,p[j].y);
                    if(dis<=p[i].r*p[i].r)
                    {
                        p[j].hp-=3*p[i].hp;
                        if(p[j].hp<=0)
                            p[j].g=1;
                        else
                            p[i].g=1;
                    }
                }
        }
    }
 
    for(int i=1; i<=n; i++)
    {
        if(p[i].g==1)
            cout<<"No"<<endl;
        else
            cout<<"Yes"<<endl;
    }
}
/**************************************************************
    Problem: 2692
    User: 20031010235
    Language: C++
    Result: 正确
    Time:50 ms
    Memory:1744 kb
    通过码:jRV2XEoytyexTCfJJpvCjVdUcfY
****************************************************************/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值