CSP-X模拟赛仲弘屹补题报告

一、题目梗概

1.独木桥(bridge)(0分,赛后通过)

2.移动棋子(chess)(60分,赛后通过)

3.动物园(zoo)(10分,赛后通过)

4.摧毁(destroy)(100分)

二、补题报告

T1:

题目描述

长度为 L 米的独木桥上有 n 个人,他们每个人都想以最快的时间离开危险的独木桥。已知每个人在独木桥上的行走速度为 1 米 / 秒 ,每个人只要能走到独木桥的两个端点中的其中一个就可以离开独木桥。
由于独木桥的桥面宽度很窄,只能容纳一个人通过,当两个人相遇时,他们无法交错通过,只能各自调转方向,继续沿反方向行走。
给你独木桥上的人数 n ,独木桥的长度 L , 第 i 个人的初始位置到独木桥左端点的距离a​i​​ 米(每个人开始的朝向未知,但他们可以根据需要随时调转行走的方向)。
请计算出所有人同时出发,全部都离开独木桥所需的最短时间。

输入格式(输入文件为 bridge.in)

第一行一个整数 n ,表示人数。
第二行一个整数 L ,表示独木桥的长度(米)。
第三行是a​1​​,a​2​​ …a​n​​ ,其中a​i​​ 表示第 i 个人初始位置到独木桥左端点 的距离。

输出格式(输出文件为 bridge.out)

输出一行一个整数,表示所有人都离开独木桥所需的最短时间。

输入样例 #1
 
  1. 3
  2. 10
  3. 2 6 7
输出样例 #1
 
  1. 4
样例一说明

说明:三个人同时出发,第一个人向左走,需要 2秒离开桥,第二个人向右走需要44秒离开桥,第三个人向右走需要3秒离开桥。所以,4秒后,三个人都离开了独木桥。

输入样例 #2
 
  1. 7
  2. 214
  3. 11 12 7 13 176 23 191
输出样例 #2
 
  1. 38
数据范围

对于 50% 的数据:1≤n≤1E3​​ ;
对于 100% 的数据:1≤n≤1E​6​​ ,1≤L≤1E​6​​ ,0≤a​i​​≤L。

思路:这个题本来可以AC的,结果忘记头文件了,最后编译错误,当时DEV-C++没检测出来。

AC代码:

#include<iostream>
#include<cstdio>
#include<climits>        //本人忘记的头文件
using namespace std;
int l,n;
const int N=1e6+2;
int a[N];
int main(){
    //freopen("bridge.in","r",stdin);
    //freopen("bridge.out","w",stdout);
    scanf("%d%d",&n,&l);
    for(int i=1;i<=n;++i){
        scanf("%d",a+i);
    }
    int maxx=INT_MIN;
    for(int i=1;i<=n;++i){
        a[i]=min(a[i],l-a[i]);
        maxx=max(maxx,a[i]);
    }
    printf("%d",maxx);
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

T2:

题目描述

一维的棋盘上有无限多个格子,每个格子都有一个编号,最中间的格子编号为 00 ,00 号格子向右依次编号为 1,2,3,… ,向左依次编号为 −1, −2, −3,… 。
小明的目标是要将一枚棋子从 x 号格子移动到 y 号格子。
每一次操作有两种选择:
操作 1 :向右移动 1 个格子。
操作 2 :从当前棋子所在的 a 号格子,直接跳到 −a 号格子(如:可以从 6 直接跳到 −6 ,也可以从 −6 直接跳到 6 )。
可以证明,无论整数 x 和 y 的值是多少,目标总是可以实现的。
请你设计程序,帮小明计算把棋子从 x 号格子移动到 y 号格子需要的最少操作次数。

输入格式(输入文件为 chess.in)

一行,两个整数 x 和 y , 表示要将棋子从 x 号格子移动到 y 号格子。

输出格式(输出文件为 chess.out)

一个整数,表示小明把棋子从 x 号格子移动到 y 号格子需要的最少操作次数。

输入样例 #1
 
  1. 10 20
输出样例 #1
 
  1. 10
样例一说明

说明:需要进行10次操作1。

输入样例 #2
 
  1. 10 -10
输出样例 #2
 
  1. 1
样例二说明

需要进行1次操作2

输入样例 #3
 
  1. -10 -20
输出样例 #3
 
  1. 12
样例三说明

说明:先进行 1 次操作 2 ,然后进行 10 次操作 1 ,最后进行 1 次操作 2 。

数据范围

对于 30% 的数据:|x|≤100,|y|≤100 ;
对于 100% 的数据:x,y都为整数;|x| ≤ 10^9,|y|≤10^9;x,y不相等。
有 40% 的数据,|x|>|y|。
有 40% 的数据,|x|<|y|。
有 20% 的数据,|x|=|y|。

思路:分情况讨论,结果60行代码,才60分。

AC代码:

#include<iostream>
#include<cmath>
using namespace std;
int x,y;
int ans=1000000001;
int main() {
    cin>>x>>y;
    if(x<=y) { //x可以直接右移到y
        ans=min(ans,y-x);
    }
    if(x<=-y) { //x可以右移到-y,然后变为y
        ans=min(ans,-y-x+1);
    }
    if(-x<=y) { //x可以变为-x,右移到y
        ans=min(ans,y-(0-x)+1);
    }
    if(-y>=-x) {//x可以变为-x,右移到-y,再变为-x
        ans=min(ans,-y-(-x)+2);
    }
    cout<<ans;
    return 0;
}

T3:

题目描述

某动物园里有n个场馆和m种动物(m≤n)。

n个场馆的编号分别用 1,2,3,..表示;m种动物的编号分别用 1,2,3,..,m 表示。每一个场馆中只饲养了一只动物,不同的场馆可能饲养着相同种类的动物。

这个动物园的门票比较特殊,游客在购买门票时必须说明要参观的场馆的起止编号a和b(起止编号会打印到游客购买的门票上),代表游客只能参观动物园的第a个场馆至第b个场馆(包含 a,b)里的动物,其他的场馆不能去。门票按一个场馆十元收费。

如果你购买的门票的起止场馆编号是 3 到 8,那么你需要花 60 元钱购买门票,只能观看3,4,5,6,7,8 号场馆的动物。

小明希望看到动物园内所有种类的动物,同时小明是个非常节约的孩子,他希望花最少
的钱买门票。 请你帮小明计算:他最少需要花费多少钱买门票才能看到所有种类的动物(同
一种动物他可能不止看一个)。注意:小明只能买一张门票。

输入格式(输入文件为 zoo.in)

第一行两个整数 n,m,分别表示动物园内的场馆数量及动物种类数量。

第二行是x​1​​,x​2​​,⋯,x​n​​,其中x​i​​表示第i个场馆中的动物种类编号。

输出格式(输出文件为 zoo.out)

一行一个整数p,表示小明的门票费用。

输入输出样例

样例 1 输入

 
  1. 12 5
  2. 2 5 3 1 3 2 4 1 1 5 4 3

*样例 1 输出

 
  1. 60

样例 11 说明:花费最少的其中一种购票方案选择是 a=2,b=7 ,表示购买场馆 2,3,4,5,6,72,3,4,5,6,7的门票,分别看到的动物是5,3,1,3,2,45,3,1,3,2,4,其中动物33小明看了两个。

数据范围

对于 30% 的数据,有n≤200,m≤20。
对于 60% 的数据,有n≤1000,m≤1000。
对于 100% 的数据,有1≤n≤1E6​​,1≤x​i​​≤m≤2×1E3​​

思路:当时没思路,最后实在不行了,直接暴力扫描,得了10分。

AC代码:

#include<iostream>
#include<cmath>
using namespace std;
const int N=1000010;
const int M=2010;
int n,m;
int l=1;//左端点
int cot=0;//l到i之间动物的种类
int a[N];//ai保存i号场馆存放了什么动物
int b[M];//保存l到i之间每种动物出现的次数
int main() {
    scanf("%d %d",&n,&m);
    int ans=n;
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        if(b[a[i]]==0) cot++;
        b[a[i]]++;
        if(cot==m) { //l右移
            for(int j=l; j<=i; j++) {
                if(b[a[j]]>1) {
                    l++;
                    b[a[j]]--;
                }
                else break;
            }
            ans=min(ans,i-l+1);
        }
    }
    printf("%d",ans*10);
    return 0;
}

T4:

题目描述

坐地日行八万里,巡天遥看一千河。

2077年,人类不仅仅是赛博科技得到了发展,太空技术也已经得到了极大的发展。地球的不同外轨道上已经充斥着各种功能用途的人造卫星。因为一个轨道上的卫星数量是有上限的,且卫星更新换代速度很快,如果想要发射新的卫星,需要把所有旧的卫星摧毁。

人类有两种不同的武器可以摧毁卫星,具体如下(其中PW为新的能量单位):
(1)使用定点激光武器花费 1 PW 的代价摧毁任意轨道上指定的一个卫星。
(2)使用脉冲轨道武器花费 c PW 的代价把某一轨道上的所有卫星摧毁。

现在有n个旧卫星分布在不同的外轨道上,你的任务是摧毁这些旧卫星。给出这n个卫
星的轨道编号,求将这些卫星全部摧毁的最小代价是多少?

输入格式( 输入文件名为 destroy.in)

第一行一个正整数T,表示测试数据组数。

接下来对于每组测试数据(注意:每组测试数据有22行数据,以下共2∗T行数据):

第一行两个正整数n和c表示需要摧毁的卫星数量和使用脉冲轨道武器的代价。

第二行 是x​1​​,x​2​​,⋯,x​n​​,其中x​i​​表示第i个卫星的轨道编号。

输出格式( 输出文件名为 destroy.out)

输出T行答案,对于每组测试数据,输出一行一个整数表示摧毁所有卫星的代价。

输入输出样例

样例 1 输入

 
  1. 4
  2. 10 1
  3. 2 1 4 5 2 4 5 5 1 2
  4. 5 2
  5. 3 2 1 2 2
  6. 2 2
  7. 1 1
  8. 2 2
  9. 1 2

样例 1 输出

 
  1. 4
  2. 4
  3. 2
  4. 2

样例说明: 对于第一组测试数据,使用脉冲武器的代价为 1 PW。轨道 11 上有 22 个卫星,轨道 2 上有 3 个卫星,轨道4 上有 2 个卫星,轨道 5 上有 3 个卫星。因此对于轨道 1、2、4、5,均使用脉冲武器各花费 1PW 的代价可全部摧毁,总的代价为 4 PW,很显然该方案为总代价最小方案。

对于第二组测试数据,使用脉冲武器的代价为 2 PW。轨道 1 上有 1 个卫星,轨道2 上有3 个卫星,轨道 3 上有 1 个卫星。因此,对于轨道 1 采用激光武器,轨道 2 采用脉冲武器,轨道 3 采用激光武器可全部摧毁所有卫星,总的代价为 4 PW,很显然该方案使得总代价最小。

数据范围

对于 30% 的数据,T=1,1≤n≤10,1≤a​i​​≤10,1≤c≤10;
对于 60% 的数据,1≤n≤1E​3​​,1≤a​i​​≤1000,1≤c≤100;
对于 100% 的数据,1≤T≤10,1≤n≤1E6​​,1≤a​i​​≤1E​6​​,1≤c≤100, 且所有测试数据的n加起来不超过1E6​​

思路:定义一个桶,遍历的时候比较一下和C的大小,加到累加器里。

AC代码:

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int N=1000010;
int t,n,c;
int num[N];
int main() {
    scanf("%d",&t);
    while(t--) {
        int k,mmin=N,mmax=0;
        scanf("%d %d",&n,&c);
        memset(num,0,sizeof(num));
        for(int i=1; i<=n; i++) {
            scanf("%d",&k);
            num[k]++;
            mmin=min(mmin,k);
            mmax=max(mmax,k);
        }
        int ans=0;
        for(int i=mmin; i<=mmax; i++) {
            if(num[i]>=c) ans+=c;
            else ans+=num[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值