B-信息学奥赛CSP真题(入门组真题)3题

文章讨论了如何在CSP竞赛中计算最优糖果分配和即时获奖分数线,涉及整数操作、算法优化和边界条件处理。
摘要由CSDN通过智能技术生成

1797: 分糖果(CSP-J 2021 T1)

题目描述

红太阳幼儿园有 n� 个小朋友, 你是其中之一。保证 n≥2�≥2 。
有一天你在幼儿园的后花园里发现无穷多颗糖果, 你打算拿一些糖果回去分给幼儿园的小朋友们。 由于你只是个平平无奇的幼儿园小朋友, 所以你的体力有限, 至多只能拿 R� 块糖回去。 但是拿的太少不够分的, 所以你至少要拿 L� 块糖回去。保证 n≤L≤R�≤�≤� 。 也就是说, 如果你拿了 k� 块糖, 那么你需要保证 L≤k≤R�≤�≤� 。
如果你拿了 k� 块糖, 你将把这 k� 块糖放到篮子里, 并要求大家按照如下方案分糖果:只要篮子里有不少于 n� 块糖果,幼儿园的所有 n� 个小朋友(包括你自己)都从篮子中拿走恰好一块糖, 直到篮子里的糖数量少 于 n� 块。此时篮子里剩余的糖果均归你所有一一这些糖果是作为你搬糖果的奖励。
作为幼儿园高质量小朋友, 你希望让作为你搬糖果的奖励的糖果数量(而不是你最后获得的总糖果数 量!)尽可能多; 因此你需要写一个程序, 依次输入 n,L,R�,�,�, 并输出你最多能获得多少作为你搬糖果的奖 励的糖果数量。

输入

输入一行, 包含三个正整数 $n, L, R$, 分别表示小朋友的个数、糖果数量的下界和上界。

输出

输出一行一个整数,表示你最多能获得的作为你搬糖果的奖励的糖果数量。

样例输入 复制

7 16 23

样例输出 复制

6

提示

对于所有数据, 保证 2≤n≤L≤R≤1092≤�≤�≤�≤109 。

#include<iostream>
#include<cstdio>
using namespace std;
int n,l,r;
int main()
{
    cin>>n>>l>>r;
    if(l/n==r/n) 
        cout<<r%n;
    else 
        cout<<n-1;
    return 0;
}

2221: 直播获奖(CSP-J 2020 T2)

题目描述

NOI2130 即将举行。为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线。本次竞赛的获奖率为 w%�%,即当前排名前 w%�% 的选手的最低成绩就是即时的分数线。

更具体地,若当前已评出了 p� 个选手的成绩,则当前计划获奖人数为 max(1,⌊p∗w%⌋)max(1,⌊�∗�%⌋),其中 w� 是获奖百分比,⌊x⌋⌊�⌋ 表示对 x� 向下取整,max(x,y)max(�,�) 表示 x� 和 y� 中较大的数。如有选手成绩相同,则所有成绩并列的选手都能获奖,因此实际获奖人数可能比计划中多。

作为评测组的技术人员,请你帮 CCF 写一个直播程序。

输入

第一行有两个整数 n,w�,�。分别代表选手总数与获奖率。
第二行有 n� 个整数,依次代表逐一评出的选手成绩。

输出

只有一行,包含 n� 个非负整数,依次代表选手成绩逐一评出后,即时的获奖分数线。相邻两个整数间用一个空格分隔。

提示

样例 #1

样例输入 #1

10 60
200 300 400 500 600 600 0 300 200 100

样例输出 #1

200 300 400 400 400 500 400 400 300 300

样例 #2

样例输入 #2

10 30
100 100 600 100 100 100 100 100 100 100

样例输出 #2

100 100 600 600 600 600 100 100 100 100

提示

样例 1 解释


数据规模与约定

各测试点的 n� 如下表:

测试点编号n=�=
1∼31∼31010
4∼64∼6500500
7∼107∼1020002000
11∼1711∼17104104
18∼2018∼20105105

对于所有测试点,每个选手的成绩均为不超过 600600 的非负整数,获奖百分比 w� 是一个正整数且 1≤w≤991≤�≤99。


提示

在计算计划获奖人数时,如用浮点类型的变量(如 C/C++ 中的float、double,Pascal 中的real、double、extended等)存储获奖比例 w%�%,则计算 5×60%5×60% 时的结果可能为 3.0000013.000001,也可能为 2.9999992.999999,向下取整后的结果不确定。因此,建议仅使用整型变量,以计算出准确值。

来源

CSP-J 2020 T2

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 2401; // 四倍节点数

int n, w;
struct Tree
{
    int l, r, v;
}tr[N];

void pushup(int u)
{
    tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
}

void build(int u, int l, int r)
{
    tr[u].l = l, tr[u].r = r;
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
}

void modify(int u, int x)//树上二分
{
    if (tr[u].l == x && tr[u].r == x) tr[u].v ++ ;
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid) modify(u << 1, x);
        else    modify(u << 1 | 1, x);
        pushup(u);
    }
}

int kth(int u, int k)
{
    if (tr[u].l == tr[u].r) return tr[u].r;
    if (tr[u << 1].v >= k) return kth(u << 1, k);
    return kth(u << 1 | 1, k - tr[u << 1].v);
}

int main()
{
    scanf("%d%d", &n, &w);
    build(1, 0, 600); // 线段树就不用考虑插入 0 了
    for (int i = 1; i <= n; i ++ )
    {
        int x;
        scanf("%d", &x);
        modify(1, x);
        printf("%d ", kth(1, i - max(1, i * w / 100) + 1));
    }
    return 0;
}


2222: 优秀的拆分(CSP-J 2020 T1)

题目描述

一般来说,一个正整数可以拆分成若干个正整数的和。

例如,1=11=1,10=1+2+3+410=1+2+3+4 等。对于正整数 n� 的一种特定拆分,我们称它为“优秀的”,当且仅当在这种拆分下,n� 被分解为了若干个不同的 22 的正整数次幂。注意,一个数 x� 能被表示成 22 的正整数次幂,当且仅当 x� 能通过正整数个 22 相乘在一起得到。

例如,10=8+2=23+2110=8+2=23+21 是一个优秀的拆分。但是,7=4+2+1=22+21+207=4+2+1=22+21+20 就不是一个优秀的拆分,因为 11 不是 22 的正整数次幂。

现在,给定正整数 n�,你需要判断这个数的所有拆分中,是否存在优秀的拆分。若存在,请你给出具体的拆分方案。

输入

输入只有一行,一个整数 n�,代表需要判断的数。

输出

如果这个数的所有拆分中,存在优秀的拆分。那么,你需要从大到小输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。可以证明,在规定了拆分数字的顺序后,该拆分方案是唯一的。

若不存在优秀的拆分,输出-1。

提示

样例 #1

样例输入 #1

6

样例输出 #1

4 2

样例 #2

样例输入 #2

7

样例输出 #2

-1

提示

样例 1 解释

6=4+2=22+216=4+2=22+21 是一个优秀的拆分。注意,6=2+2+26=2+2+2 不是一个优秀的拆分,因为拆分成的 33 个数不满足每个数互不相同。


数据规模与约定

  • 对于 20%20% 的数据,n≤10�≤10。
  • 对于另外 20%20% 的数据,保证 n� 为奇数。
  • 对于另外 20%20% 的数据,保证 n� 为 22 的正整数次幂。
  • 对于 80%80% 的数据,n≤1024�≤1024。
  • 对于 100%100% 的数据,1≤n≤1071≤�≤107。

来源

CSP-J 2020 T1

#include <iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;

    if(n%2)
    {
        cout<<-1;
        return 0;
    }
    for(int i=23;i>=1;i--)
    {
        if(n >> i & 1)
            cout<< (1 << i) <<" ";
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值