2021合肥市青少年信息学科普日活动-小学组题解

新冠病毒群体免疫covid

题目描述
新冠病毒肆虐全球将近两年了,给世界各国都带来了极大的麻烦,为了最
终能战胜新冠病毒,各个国家都在加紧研发疫苗,我们国家目前已研发出了灭
活疫苗、腺病毒载体疫苗等多款不同技术的新冠疫苗,在满足自己使用的同
时,也帮助了很多的国家,一起阻遏病毒肆虐。预防胜于治疗,只有达到一定
的接种疫苗比例,即实现群体免疫,才是战胜新冠病毒的王道。研究表明,不
同的疫苗效力,实现群体免疫的人口接种疫苗比例是不同的,假设一个国家接
种疫苗的人口只要达到该国家总人口的 75%,即可实现群体免疫。请计算一个
国家需要接种多少人才能实现群体免疫。

输入
输入:输入数据共 1 行 1 个正整数,表示一个国家的人口总数,单位万人。

输出
输出:共 1 行一个正整数,表示达到群体免疫需要接种疫苗的人数,四舍五入,
单位万人。
样例 1:
输入:(covid.in)
100
输出:(covid.out)
75
数据范围:100≤人口总数≤100000

#include<bits/stdc++.h>
using namespace std;
int main() {
    double n;
    scanf("%lf", &n);
    printf("%d",(int)(n * 0.75 + 0.5));
    
    return 0;
}

整理书本(book)

题目描述
又一个学期结束了,又积累了好多本书,你决定好好整理一下,整理时共有
三种操作,规则如下:
1 p 表示把编号为 p 的书放到最前面
2 p 表示把编号为 p 的书放到最后面
3 p q 表示把编号为 p 的书放到编号为 q 的书的后面
1、2、3 分别代表整理操作的种类,p、q 表示书的编号,他们之间由空格分
隔;已知在整理之前,所有书从 1 开始依次编号排放。

输入
输入:共 m+1 行。第一行有两个由空格分隔的正整数 n 和 m,分别表示 n 本书
和 m 次整理操作,接下来 m 行,每行有 2 个或 3 个由空格分隔的正整数,
对应上述三种整理操作。

输出
输出:共 1 行,经过整理后的书本顺序,书本间用空格隔开。

样例输入

10 4
1 3
2 4
3 3 6
3 1 5

样例输出

2 5 1 6 3 7 8 9 10 4

提示
数据范围:1≤n,m≤100000

解题思路
由于涉及到大量的插入删除操作,故使用传统的暴力思想进行解题必然超时,因此我们考虑采用链表快速实现插入和删除操作,便可轻松AC。同时题目给出的三种操作中还要注意讨论一下,以免造成运行错误和答案错误。
1 p 表示把编号为 p 的书放到最前面
2 p 表示把编号为 p 的书放到最后面
对于第一、二种操作需要考虑p的位置在最前面和最后面以及在最中间的位置,然后再进行删除,最后在把p插入最前面和最后面的位置即可。
3 p q 表示把编号为 p 的书放到编号为 q 的书的后面
首先要考虑p和q相等的情况,这种情况直接continue就行,不用进行任何操作,然后再和第一二种操作方法一样,考虑p的位置 进行删除,最后将p插入q的位置之后即可。

我的解法用的是动态链表,仅供参考,各位也可以用静态链表等不同的方法解出。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int n, m;
struct node
{
    /* data */
    int data;
    node *next, *pre;
}*tail, *stop;
struct node *position[maxn];
node *init() {
    node *k, *head, *a;
    head = (node*)malloc(sizeof(node*));
    head -> next = head -> pre = NULL;
    a = head;
    for(int i = 1; i <= n; i++) {
        k = (node *) malloc (sizeof(node *));
        k -> data = i;
        k -> next = a -> next;
        k -> pre = a;
        a -> next = k;
        a = k;
        position[i] = k;
    }
    tail = position[n];
    a -> next = NULL;
    return head;
}
int main() {
    //freopen("test.in","r",stdin);
    scanf("%d%d", &n, &m);
    node *List = init();
    stop = position[1];
    /*
    while (stop != NULL)
    {
        cout << stop -> data << " ";
        stop = stop -> next;
    }
    cout << endl;
    */
    while(m--) {
        int op, p, q;
        scanf("%d", &op);
        if(op == 1) {
            scanf("%d", &p);
            List = position[p];
            node *r  = List -> pre;
            if(List -> data == tail -> data) {
                r -> next = NULL;
                tail = r;
            } 
            else if(List -> data == stop -> data) continue;
            else {
                r -> next = List -> next;
                List -> next -> pre = r;
            }
            List -> next = stop;
            stop -> pre = List;
            stop = List;
            stop -> pre = NULL;
        }
        else if(op == 2) {
            scanf("%d", &p);
            List = position[p];
            node *r  = List -> next;
            if(List -> data == stop -> data) {
                r -> pre = NULL;
                stop = r;
            } 
            else if(List -> data == tail -> data) continue;
            else {
                List -> pre -> next = r;
                r -> pre = List -> pre;
            }
            List -> pre = tail;
            tail -> next = List;
            tail = List;
            tail -> next = NULL;
        }
        else {
            scanf("%d%d", &p, &q);
            if(p == q) continue;
            node *l = position[q], *r = position[p];
            if(r -> data == stop -> data) {
                stop = stop -> next;
                stop -> pre = NULL;
            }
            else if(r -> data == tail -> data) {
                tail = tail -> pre;
                tail -> next = NULL;
            }
            else {
                List = r -> pre;
                List -> next = r -> next;
                r -> next -> pre = List;
            }
            if(l -> data != tail -> data) {
                r -> next = l -> next;
                l -> next -> pre = r;
                l -> next = r;
                r -> pre = l;
            } else {
                l -> next = r;
                r -> pre = l;
                tail = r;
                tail -> next = NULL;
            }
        }
    }
    List = stop;
    while (List != NULL)
    {
        //List = List -> next;
        printf("%d ", List -> data);
        List = List -> next;
    }
    return 0;
}

时空穿梭机(cycraft)

题目描述

随着游戏的深入进行,你也获得了很多的武器装备,每获取一件武器装备都
需要付出一定的代价。假设有一个时间轴,其上记录了在某个时间点对应有一个
武器装备,我们赋予每一个时间点 ti 时刻对应的武器装备 i 的威力值为 wi。此时
你拥有一台时空穿梭机,可以在时间轴上任意穿梭,假设穿梭到时间点 t,定义
t 时间点到 ti 时间点获取 i 武器装备的代价为|t-ti|*wi。请计算在哪个 t 时间点获
取所有武器装备需付出的总代价最小,输出最小的总代价。获取每一件武器装备
必须都从 t 时间点出发,返回 t 时间点的代价为 0;|t-ti|表示 t-ti 的绝对值。

输入
输入:共 n+1 行,第一行一个正整数 n,表示武器装备总数,接下来 n 行,每行
两个用空格分隔的整数,分别表示时间 ti 和该时刻对应的武器装备的威
力值 wi。

输出
输出:共 1 行一个整数,表示获取所有武器的最小代价。

暴力AC代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int t[maxn], w[maxn];
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d%d", &t[i], &w[i]);
    int ans = INT_MAX;
    for(int time= -1000; time <= 1000; time++) {
        int sum = 0;
        for(int i = 0; i < n; i++) {
            sum += abs(time - t[i]) * w[i];
        }
        ans = min(ans, sum);
    }
    cout << ans;
    return 0;
}

感谢一颗小码农所提供的更优解,以下是一颗小码农大佬所提供的解题思路和代码:
虽然该题用暴力能过,但是由于代价曲线呈V字形,所以可以用二分法优化一下。

#include<bits/stdc++.h>
using namespace std;
int getSum(vector < pair < int, int >>& nums, int mid) {
    int n = nums.size();
    int sum = 0;
    for (int j = 0; j < n; ++j) {
        sum += abs(mid - nums[j].first) * nums[j].second;
    }
    return sum;
}
int main() {
    int n;
    cin >> n;
    vector < pair < int, int >> nums(n);
    for (int i = 0; i < n; ++i) {
        int time, w;
        cin >> time >> w;
        nums[i] = {
            time, w 
        };
    }
    int res;
    int left = - 1000;
    int right = 1000;
    while (left <= right) {
        int mid = left + (right - left)  / 2;
        int sum1 = getSum(nums, mid);
        int sum2 = getSum(nums, mid + 1);
        if (sum1 < sum2) {
            res = sum1;
            right = mid - 1;
        }
        else {
            left = mid + 1;
        }
    }
    cout << res;
    return 0;
}

老鼠爱美食(mouse)

题目描述

在一条道路上有很多从 1 开始依次编号的老鼠最爱的美食,假设每种美食都
有无限多,而老鼠们随机闪现在任一个美食旁,然后依次尝试美食,至少需要尝

试到第一次出现时的下一个美食为止,求哪两种相邻的美食被老鼠们尝试的次数
最多,输出最多的次数即可。保证每只老鼠出现和停止的美食编号都不同。

输入
输入:输入数据有 n+1 行,第一行表示老鼠数量 n,接下来 n 行每行都有两个数,
分别表示老鼠第一次出现的美食编号,和停止的美食编号

输出
输出:一行一个正整数,表示最多的次数。

样例输入

3
1 4
2 5
3 7

样例输出

3

样例解释:
共有 3 只老鼠,第一只依次尝试了 1-2-3-4 共 4 种美食;第二只依次尝试了
2-3-4-5 共 4 种美食;第三只依次尝试了 3-4-5-6-7 共 5 种美食。相邻的 3-4 美食
被尝试了 3 次。
数据范围:2≤n≤10000,
美食种类保证在 int 范围内,每只老鼠出现和停
止的美食编号都不同。

解题思路
差分找出出现次数最多的区域即可。

#include<bits/stdc++.h>
using namespace std;
int main() {
    int n;
    scanf("%d", &n);
    int l, r;
    map <int, int> mp;
    for(int i = 0; i < n; i++) {
        scanf("%d%d", &l, &r);
        mp[l]++, mp[r+1]--;
    }
    int ans = 0, cur = 0;
    for(auto &i:mp) {
        cur += i.second;
        ans = max(ans, cur);
    }
    printf("%d", ans);
    return 0;
}
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值