暑假训练赛(3)赛后总结

目录

智能服药助手

屿汐打怪

狗汪

元芳组合数

总结 


智能服药助手

描述

智能看护中很重要的环节是安排需要服药的老年人的服药计划。

已知机器人需要照顾的某位老年人需要服用 N 种药物,但某些药物不宜间隔过短服用 —— 比如降糖药一般遵医嘱日服 3 次,两次之间需要间隔至少 4 小时。

当需要服用的药物比较多,医嘱比较复杂时,如何保证每位老人的服药计划是安全合理的,就成为一个挑战。

本题给定一套服药计划,请你检查一下计划是否存在问题。

输入

第一行给出两个整数N,M,表示老人需要服用N种药物,一共有M条记录。

接下来一行给出 N 个用空格隔开的整数Ti,表示编号为i的药物间隔至少Ti个单位时间服用,如果Ti为-1,则说明这种药物没有间隔要求。

接下来的 M 行,每行给出一条服药计划的记录。

格式为:首先给出两个整数 t 和 k ,表示服药的时刻为 t,服用了 k 种药物,然后列出 k 个数,每个数对应 t 时刻要吃的药物种类的编号。

输出

按照输入顺序检查每一条记录中的每一种药物。如果在 Y 时刻不宜服用药物 X,则在一行中输出:

Don't take X at Y!

注意:老人收到提醒后会按照提醒不服用指定的药物(也就是说,本次服药不会更新上一次服用该药的时间)。

输入样例 1 

10 6
1 2 3 4 5 -1 -1 -1 -1 -1
0 1 1
1 2 1 2
2 1 2
3 2 1 3
5 3 1 3 4
6 2 1 4

输出样例 1

Don't take 2 at 2!
Don't take 3 at 5!
Don't take 4 at 6!

提示

image.png

image.png

-1<=Ti<=100且Ti≠0

T没有保证递增,判断时请改成差的绝对值,比如上次服药时间是10,然后给了t=5对于服药间隔<=5的都不用提醒,继续更新这次服药时间=5


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

const int N = 1010;
int T[N]; // 存储药的间隔时间
int last[N]; // 记录这个第i种药最早服用时间

struct Node // 用一个结构体来记录每次服药的情况,用一个动态数组来记录用药情况显的更加合理
{
    int t;
    vector<int> e;
}p[N];

int n,m;

int main()
{
    cin >> n >>m;
    for(int i = 1; i<= n ;i ++)
    {
        cin >> T[i];
        if(T[i] == -1)
            T[i] = 0; // 若为-1则没有服药的间隔时间
    }
    
    for(int i = 1; i<= m ; i ++)
    {
        cin >> p[i].t;//每次服用的编号
        int q; //服了多少药
        cin >> q; 
        for(int j = 1; j <= q; j ++)
        {
            int x; 
            cin >> x;
            p[i].e.push_back(x);//动态数组来记录用药
        }
    }
    memset(last,-1,sizeof last); //对last数组进行初始化
    for(int i = 1; i <= m ; i ++)
    {
        int now = p[i].t;
        for(int j = 0; j < p[i].e.size(); j ++)
        {
            int id = p[i].e[j];
            if(last[id] != -1 && abs(last[id] - now) < T[id]) //判断是否现在可以用药
            {
                printf("Don't take %d at %d!\n",id,now);
            }
            else
                last[id] = now; // 更新last数组
        }
    }
    return 0;
}

 这道题灵活的运用了数组,用数组来处理了药的时间持续问题问题;用动态数组来较为巧妙的来储存每次的用药情况。


 

屿汐打怪

描述

已知地图上有n只怪物,每只怪物的血量为2,攻击力为ai。屿汐准备去地图上杀怪,他的初始血量为m。

屿汐的每次攻击伤害为1,而且每次杀怪时屿汐先攻击。

屿汐每次攻击后,若怪物没有死亡(即血量大于0),屿汐都会承受一次怪物攻击力的伤害。但是屿汐可以在战斗开始前喝血药,每个血药可以回复

k 点血量。也就算说,x 瓶血药可以将屿汐的初始血量提高到m+x*k。

每只怪物都是不可复活的,当屿汐血量为0或负数时死亡,屿汐在选择打一个怪时,在该怪物被打死前不会更换目标。

请问,屿汐初始带了x瓶血药时,最多可以杀死多少只怪物。

上述问题会重复q次,每次询问都是独立的。

输入

第一行输入三个正整数 n,m,k,代表地图上怪物的数量,屿汐的初始血量,每瓶血药回复的血量。

接下来n行,每行输入两个正整数ai,代表每只怪物的攻击力。

接下来一行输入一个整数q,代表询问次数。

接下来的一行,输入q个正整数x,代表每次询问中屿汐携带的血药数量。

输出

输出一行q个正整数,代表屿汐携带x瓶血药时能击杀的最多怪物数量。

输入样例 1 

3 1 2
1
2
2
3
1 2 3

输出样例 1

1 2 3

提示

1≤n,m,k,ai,q,x≤1e5


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

const int N = 1e5 + 10;
int a[N];
int n,h,k;

signed main()
{
    memset(a,0,sizeof a);
    cin >> n >> h >> k;
    for(int i = 1; i <= n; i ++)
        cin >> a[i];
    sort(a+1,a+1+n);
    for(int i =1; i <= n ; i ++) 
        a[i] += a[i-1];
    int q;
    cin >> q;
    for(int i = 1; i <= q; i ++)
    {
        int x;
        cin >> x;
        int tmp = h + x * k; // 本次询问时小红的血量,直接全喝了
        int l = 0, r = n;
        while(l<r)
        {
            int mid = (l + r + 1) / 2;
            if(a[mid] < tmp) l = mid; // 二分寻找小红打怪的上限,降低时间的复杂度
            else r = mid - 1;
        }
        cout << l << " ";
        
    }
    return 0;
}

 思路解析:

                由于怪的血量均为 2, 小红的伤害为 1, 而且小红打怪的时候都是先手,所以如果小红选择打这个怪的话必定会受到这个怪一次有且只一次的攻击,所以每次怪构成的伤害就是他的攻击力。如果要求最大的击杀量的话,那么小红就需要优先击杀那些伤害低的怪,所以对怪的伤害进行排序。如果题目为单次询问的话,我们可以对怪进行枚举,当总伤害大于等于的时候结束枚举。但是题目要求的是多次询问,这时候时间复杂度就为O(n^q),这个时间复杂度肯定是AC不了这道题的(我就错在这里www)。所以我们要进行对怪伤害进行前坠和处理,然后再二分查找。


狗汪


描述

实验室t汪的狗汪声越来越大,每天都能听到不同大小的狗汪声

现给定n个狗汪声的大小ai,求大小不同的狗汪声有多少?

输入

第一行一个正整数n

第二行n个狗汪声的大小

输出

输出有多少个大小不同的狗汪声

输入样例 1 

6
1 4 1 2 2 1

输出样例 1

3

输入样例 2 

1
1

输出样例 2

1

输入样例 3 

11
3 1 4 1 5 9 2 6 5 3 5

输出样例 3

7

提示

1<=n<=1000

0<=a[i]<=10^100

 

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

signed main()
{
    set<string> aa; // map<string,int> aa; 
    string a;
    int n;
    cin >> n;
    for(int i = 0 ; i < n; i ++)
    {
        cin >> a;
        aa.insert(a); // aa[a] ++;
    }
    cout << aa.size();
    return 0;
}

 这道题吃了没有文化的亏www~~~

但是也不是不能写如果你不知道map和set的话,只不过代码长一点......

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

string a[1010];

int main()
{
    int n, cnt = 0;
    cin >> n;
    for(int i = 0 ; i < n; i ++)
        cin >> a[i];
    for(int i = 0; i < n; i ++)
    {
        int k = 1;
        for(int j = i - 1; j >= 0; j --)
        {
            if(a[i] == a[j])
            {
                k = 0;
                break;
            }
        }
        if(k)
            cnt ++;
    }
    cout << cnt;
    return 0;
}

元芳组合数

描述

元芳从 1∼n 这 n个整数中随机选出 m个,输出所有可能的选择方案。

输入

两个整数 n,m,在同一行用空格隔开。

输出

按照从小到大的顺序输出所有方案,每行 1个方案。

首先,同一行内的数升序排列,相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。

输入样例 1 

5 3

输出样例 1

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5 

提示

n>0,

0≤m≤n,

n+(n−m)≤25

模板题,题目要求列出从 n 个数中选 m 个数的所有情况。本题只需用 dfs 跑出来
所有情况。只要枚举的数超过 m 就退出到前一层。 dfs 因同一行内的数需升序排
列,所以需用一变量 start 保存已枚举到哪一个数,其他的与全排列相似。

 

#include<iostream>
using namespace std;

const int N=30;
int a[N];
bool st[N];
int n,m;

void dfs(int u,int start)
{
    if(u==m+1)
    {
        for(int i=1;i<=m;i++) printf("%d ",a[i]);
        puts("");
        return;
    }
    for(int i=start;i<=n;i++)
    {
        if(!st[i])
        {
            a[u]=i;
            st[i]=true;
            dfs(u+1,i+1);
            st[i]=false;
        }
    }
}

int main()
{
    cin >> n >> m;
    dfs(1,1);
    return 0;
}

总结 

这次题目难度其实不难,但是临场写的时候却漏洞百出,希望下次可以发挥的更好,冷静思考,AC更多题!!!

加油!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小腾子喔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值