CodeForces Educational Codeforces Round 161 (Rated for Div. 2) D.Berserk Monsters 难度1900

题目:

Monocarp 正在玩电脑游戏(又一次)。猜猜他在做什么?没错,杀怪。

一排有 n个怪物,编号从 1 到 n 。其中 i号 个怪物有两个参数:攻击值等于 ai,防御值等于 di 。为了杀死这些怪物,莫诺卡普给它们施放了狂暴咒语,因此它们会互相攻击,而不是攻击莫诺卡普的角色。

战斗由 n个回合组成。每回合都会发生以下情况:

  • 首先,每个 i活着的怪物都会对左边最近的活着的怪物(如果存在)和右边最近的活着的怪物(如果存在)造成 ai 伤害;
  • 然后,每个在本回合中受到超过 dj 伤害的活着的怪物 j 死亡。也就是说,当且仅当 j 怪物的防御值 dj 严格小于它在本轮受到的总伤害时,它才会死亡。

计算每一轮中死亡的怪物数量。

输入:

第一行包含一个整数 t ( 1 ≤ t ≤ 10^4) - 测试用例数。

每个测试用例由三行组成:

  • 第一行包含一个整数 n ( 1≤n≤3⋅10^5 );
  • 第二行包含 n 个整数 a1,a2,…,an1,2,…, ( 1≤ai≤10^9 )( 1≤ai≤10^9 );
  • 第三行包含 n 个整数 d1,d2,…,dn1,2,…, ( 1≤di≤109 )。

输入的附加限制:所有测试用例的 n 之和不超过 3⋅10^5。

输出:

对于每个测试案例,打印 n 个整数。 i 个整数应该等于在 i 个回合中死亡的怪物数量。

样例1

3
5
3 4 7 5 10
4 9 1 18 1
2
2 1
1 3
4
1 1 2 4
3 3 4 2
3 1 0 0 0 
0 0 
1 1 1 0 

思路:

首先思考一个怪物在什么情况下会死亡呢

两种情况

  1. 一开始的时候就被周围的怪物弄死了
  2. 剩下的就是第一回和没死的,假设上一回和没死的怪物,周围的怪都没死,那么他受的伤害和上一回和相同,依旧可以存活,也就是说只有上一回合旁边的怪物死了,才有可能死亡。

解决办法:

  • 对于第一种情况,只能进行预处理
  • 对于第二种情况,那就是记录上一回合死亡的怪物然后再出来与他相邻的怪物

怎么快速获取死亡怪物附近的两个怪物呢,可以记录左右节点,利用数组存储,实现复杂,对于连续死多个处理麻烦,利用链表,又无法快速获取下标。

使用stl容器的set,利用其中的upper_bound快速找到他的下一个位置的怪物,那么怎么找前一个呢,利用greater<int>将set反序,由于upper_bound找到的是等于自己的下一个元素,那么对于反序的就是小于自己的第一个元素,也就是前一个坐标,然后判断是否存在,在利用左右两边怪物的攻击判断是否能够击杀,能就用队列现存下来,然后再在set当中删除他的下标,再循环此操作

#include<bits/stdc++.h>
using namespace std;

#define x first
#define y second 
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define ls u << 1
#define rs u << 1 | 1
#define all(x) x.begin(),x.end()
// #define int long long
#define i128 __int128

inline int gcd(int a, int b) {return b > 0 ? gcd(b, a % b) : a;}
inline int lowbit(int x) {return x & (-x);}
int qmi(int a, int b, int mod){int res = 1;while(b) {if(b & 1) res = res * a % mod;a = a * a % mod;b >>= 1;}return res;}
inline i128 read(){i128 x = 0, f = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;}
inline void print(i128 x){if(x < 0){putchar('-');x = -x;}if(x > 9)print(x / 10);putchar(x % 10 + '0');}

typedef long long ll;
typedef pair<int, int> PII;
typedef pair<PII, int> PIII;
const int N = 1e5 + 10, inf = 0x3f3f3f3f, mod = 1e9 + 7;

/*
int mp[N + 1];
vector<int>prim;
void primes() {
    for (int i = 2; i <= N; i++) {
        if (!mp[i]) {
            mp[i] = i;
            prim.push_back(i);
        }
        
        for (auto p : prim) {
            if (i * p > N) break;
            mp[i * p] = p;
            if (i % p == 0) break;
        }
    }
}
*/

/*
int fact[N], infact[N]; // 组合数
int C(int a, int b) {return fact[a] * infact[b] % mod * infact[a - b] % mod;} 
void combination() {fact[0] = infact[0] = 1;for(int i = 1; i < N; i ++) {fact[i] = fact[i - 1] * i % mod;infact[i] = fact[i] * qmi(i, mod - 2, mod) % mod;}}
*/

void solve()
{
    int n; cin >> n;
    vector<int>a(n + 1, 0), d(n + 1, 0);
    set<int>stx;
    set<int, greater<int>>sti;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1; i <= n; i ++) cin >> d[i], stx.insert(i), sti.insert(i);
    
    vector<int>c(n + 2, 0);
    for(int j = 1; j <= n; j ++) {
        c[j - 1] += a[j], c[j + 1] += a[j];
    }
    
    set<int>s;
    for(int i = 1; i <= n; i ++) if(c[i] > d[i]) s.insert(i), stx.erase(i), sti.erase(i);
    
    vector<bool>stb(n + 1, 0);
    for(int j = 1; j <= n; j ++) {
        cout << s.size() << ' ';
        vector<int>v;
        for(auto t : s) {
            auto itx = stx.upper_bound(t);
            int ans = 0;
            if(itx != stx.end()) {
                int p = *itx;
                auto itxx = stx.upper_bound(p);
                auto itxi = sti.upper_bound(p);
                if(itxx != stx.end()) ans += a[*itxx];
                if(itxi != sti.end()) ans += a[*itxi];
                if(ans > d[p]) v.push_back(p);
            }
            
            auto iti = sti.upper_bound(t);
            ans = 0;
            if(iti != sti.end()) {
                int p = *iti;
                auto itix = stx.upper_bound(p);
                auto itii = sti.upper_bound(p);
                if(itix != stx.end()) ans += a[*itix];
                if(itii != sti.end()) ans += a[*itii];
                if(ans > d[p]) v.push_back(p);
            }
        }
        s.clear();
        for(auto k : v) 
            s.insert(k), stx.erase(k), sti.erase(k);
    }
    cout << '\n';
}

signed main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
} 

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值