CSP-X复赛模拟一补题报告

                                                                             CSP-X复赛模拟一补题报告
                                                                                 时间:2023年10月1日
                                                                                       S12004 张伯钧

  一、分数:
        总分:0’
        T1【爬楼梯】:0’
        T2【字符折线图】:0’
        T3【吉利数】:0’
        T4【路灯照明】:0’
  二、比赛过程:
  都直接把测试样例输出了
  第一题:
  //题目没有读懂,思路更有问题。
 1.这一楼究竟是两层还是一层。2.小可和达达上了一层楼后要是还有步数不能要。
  第二题:
  //思路没有问题,程序全是问题。
  1.数组下标变量向上是--不是++。2.先是行再是列,行是横着的,列是竖着的。
  第三题:
  //思路似乎对了,程序不停报错。
  1.我也不知道错哪了。2.忘去注释了。
  第四题:
  //题目基本没读,直接输出样例。
 1.时间不够。2.也看不懂。
三、比赛分析:
第一题:
题目描述:

        小可和达达不打算坐电梯,于是他们打算爬楼梯爬上来!小可和达达从第一层出发,小可记录了每一步迈出去的距离能够跨越多少个台阶,达达记录了迈多少个台阶能够到达下一个平台。和很多大楼类似,每次爬楼梯到达一个平台,就需要转身再爬,到达两个平台代表上了一层楼。
      请你计算一下,现在小可和达达已经到达了多少层!例如小可到了第八层,然后又向上爬了若干台阶,但是没有到第九层,那么输出第八层。
    输入描述:
    第一行两个正整数n和x,代表小可迈了n步,x个台阶能够上一楼。
    第二行n个整数,代表小可每一步迈出去的距离能够跨越多少个台阶。
    输出描述:
    如题,输出一个整数,代表现在小可和达达已经到达了多少层。
    样例输入1
    10 10
    2 5 3 7 3 1 5 4 5 5
    样例输出1
    3
    样例输入2
    3 5
    3 5 2
    样例输出2
    1
    样例输入3
    5 5
    10 10 10 10 10
    样例输出3
    3
    提示
    题目中的楼梯和现实生活中常见的楼梯结构类似,小可记录的是每一步迈出去的距离能够跨越多少个台阶,比如还剩一个台阶就能到达下一个平台,小可步子迈的再大,也只能上一个台阶。不存在一步跨越好几个平台的情况。当然,小可肯定是尽可能多地迈步。比如小可一步能跨越55个台阶,并且还是到不了下一层,那么小可这一步就一定迈了55个台阶。

数据

思路:

        把小可迈的台阶累加
        如果上了一个平台,就让楼层计数器++,然后把多余的步数清零
        比如小可的步数(n个整数)分别是2 5 5 7,而上一层平台的步数(x)是10,那么先把前两次迈的步数相加2+5=7,然后现在还差3,但下一个数是5,不是3,就让他先迈3步,到达了一个平台,那剩下那两步就不能要了,所以步数计数器清零。
代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
using namespace std;
int main(){
    long long n,a[100005],x;//定义
    cin>>n>>x;//输入
    for(int i=1;i<=n;i++){
        cin>>a[i];//输入
    }
    int c=0,sum=0;
    for(int i=1;i<=n;i++){
        c+=a[i];
        if(c>=x){//判断到了一层
            sum++;//计数器++
            c=0;
        }
    }
    cout<<sum/2+1;//输出
    return 0;
} 


第二题:
题目描述:

        字符串也是有起伏的!我们根据一个字符串,可以画出一个折线图。从第二个字符开始,如果它比它的上一个字符大,那么就是上升的,画一个/;如果和上一个字符相同,那么画一个-;如果比比上一个字符小,那么就是下降的,画一个\。并且上升的时候,要向上一行,下降的时候向下一行。具体例子如下:
字符串hkrzyqqqmi:
  /\
 /  \
/    --
       \
        \
注意控制格式,空白处使用空格填充,不要输出多余的空格。
输入描述
一个字符串,长度不超过100100,只包含小写字母。
输出描述
如题,根据输入的字符串画出折线图。
样例输入1
zyxvu
样例输出1
\
 \
  \
   \
样例输入2
abcde
样例输出2
   /
  /
 /
/
样例输入3
hhhhh
样例输出3
----
样例输入4
babababa
样例输出4
\/\/\/\
样例输入5
hikgabzph
样例输出5
 /\  /\
/  \/  \
样例输入6
abcccddddccc
样例输出6
     ---
    /   \
  --     --
 /
/
提示
当前字符和上一个字符相等时,输出的是减号而不是下划线。

数据

设n代表字符串长度:

思路: 

        如果想要100%正确那么就要用数组来实现,首先定义一个二维数组(char类型)全部初始化为空格,再定义一个控制下标的变量,每判断一次就在相应的位置放上"/","-","\"之一最后输出的时候要把后面的空格去掉,每行从后遍历找到第一次出现字符的位置记录下来,再从头输出到这。  
代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
using namespace std;
char s[205][205];
void init(){
    for(int i=0;i<=200;i++){
        for(int j=0;j<=200;j++){
            s[i][j]=' ';
        }
    }
}
int main(){
    string a;
    cin>>a;
    init();//初始化数组
    int len=a.size(),y=100,min=205,max=0;
    for(int x=1;x<len;x++){//遍历数组
        if(a[x-1]<a[x]){//递增
            if(s[y][x-1]=='/'){
                y--;
            }
            else if(s[y][x-1]=='-'){
                y--;
            }
            s[y][x]='/';
        }
        else if(a[x-1]==a[x]){//相等
            if(s[y][x-1]=='/'){
                y--;
            }
            else if(s[y][x-1]=='\\'){
                y++;
            }
            s[y][x]='-';
        }
        else if(a[x-1]>a[x]){//递减
            if(s[y][x-1]=='\\'){
                y++;
            }
            else if(s[y][x-1]=='-'){
                y++;
            }
            s[y][x]='\\';
        }    
        if(y<min){
            min=y;
        }
        if(y>max){
            max=y;
        }
    }
    int c;
    for(int i=min;i<=max;i++){
        for(int j=len-1;j>=1;j--){
            if(s[i][j]!=' '){
                c=j;
                break;
            }
        }
        for(int j=1;j<=c;j++){
            cout<<s[i][j];
        }
        cout<<endl;
    }
    return 0;
}


第三题:
题目描述:

        小可认为一个数字中如果有44这个数字就是不吉利的。相对的,其他的数字就是吉利的。吉利的数字有1,2,3,5,6,7,8,9,10,..
小可想知道,第n个吉利的数字是多少。
输入描述
第一行一个正整数t,代表有t组输入。
接下来t行,每行一个正整数n,代表小可想知道第n个吉利的数字是多少。
输出描述
对于每组输入,输出一行,代表相应的答案。
样例输入
5
1
2
14
255
12345678999999
样例输出
1
2
16
313
58737318092550

数据范围

对于20%的数据,t=1,n≤10
对于40%的数据,t≤10,n≤100
对于60%的数据,t≤10,n≤10^6
对于80%的数据,t≤5×10^5,n≤10^6
对于100%的数据,t≤5×10^5,n≤10^18

思路:​​

        非常复杂,先转九进制,因为十进制有10个数(0,1,2,3,4,5,6,7,8,9)现在要把4去掉就只剩9个数了(0,1,2,3,5,6,7,8,9)

九进制正好有九个数(0--8),现在看看下表(都是九进制,左边是不去4的右边是去掉4的) ,会发现从3往后每个数都比原来少了1

所以只需要把输入的数转成九进制,再分类输出就好了。

0 0

1 1

2 2

3 3

4 5   差1

5 6   差1

6 7   差1

7 8   差1

8 9   差1

正好九进制没有9

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
using namespace std;
int s[1000005];
long long j=1;
void f(long long x){//十进制转九进制
    while(x){
        s[j]=x%9;
        x/=9;
        j++;    
    }
}
int main(){
    long long n,a;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a);
        f(a);
        for(int t=j-1;t>=1;t--){
            if(s[t]>=4){//判断是否大于4
                s[t]++;
            }
            printf("%d",s[t]);
        }
        cout<<"\n";
        j=1;
    }
    return 0;
}


第四题:
题目描述:

        小可是一个相信光的人,他最近在研究光与距离的问题。
给定一个 2*2 的网格,每个网格都有一盏路灯,且都在格点上,即:四盏路灯的位置分别是左上角, 右上角,左下角,右下角。
路灯都是需要耗电的,且耗电量与亮度有关,如果一盏路灯的耗电量是 x ,则它可以为他所在的格子提供 x 的亮度,并且为他相邻的格子提供 x/2下取整,为他对角的格子提供 x/4下取整 的亮度
某一个格子的亮度为四盏路灯为他提供的亮度之和
现在我们对四个格子的最低亮度提出了要求,我们想要让四个格子的亮度都达到标准。你可以将每一盏灯的耗电量调节为任何一个大于等于零的整数,为了省电, 你希望四盏灯的耗电量之和尽可能的小,请问四盏灯的最小耗电量之和是多小?
输入描述
输入四个整数:a,b,c,d,分别表示左上、右上、左下、右下 四个格子要求的亮度之和。
输出描述
输出一行一个整数表示四盏灯的最小耗电量之和。
输入样例1
50 24 25 12
输出样例1
50
样例说明1
左上角的位置的灯耗电量设置为 50,其它三个位置设为 0。即可满足亮度要求
输入样例2
8 8 8 8
输出样例2
15
样例说明2
4 盏灯耗电量依次为 4 3 4 4

数据描述

对于20%的数据:1≤a,b,c,d≤50

对于70%的数据:1≤a,b,c,d≤400

对于100%的数据:1≤a,b,c,d≤1500

思路:

        二分枚举,套公式(详见注释)。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
using namespace std;
int a,b,c,d;
bool check(int mid){
    for(int i=0;i<=a;i++){
        for(int j=0;j<=d;j++){
            int need=max(a-i-j/4,d-j-i/4);
            if((mid-i-j)/2<need)  continue;
            int now=mid-i-j;//还有多少可以分配 
            int bneed=max(0,b-i/2-j/2);//b还需要多少 
            int cneed=max(0,c-i/2-j/2);//c还需要多少 
            int bb=max(0,(4*bneed-now)/3);//估算b大概区间 
            //p=b,q=c
            //p+q/4=bneed, p+q=now
            //p+q/4=bneed -> 得4p+q=4bneed 
            //4p+q=4beend -> 3p+now=4bneed
            //p=
            
            for(int k=max(0,bb-5);k<=min(now,bb+5);k++)
                if(k+(now-k)/4>=bneed&&k/4+now-k>=cneed)
                //左下提供+b>=b需要    左下>=需要
                    return true;; 
        }
    }
    return false;
}
int main(){
    cin>>a>>b>>c>>d;
    int l=0,r=a+b+c+d,ans=a+b+c+d;
    while(l<=r){//枚举最小耗电量之和 
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            r=mid-1;
        }
        else{
            l=mid+1;
        }
    }
    cout<<ans;
    return 0;
}


四、赛后总结

错点有因为注释没删而不得分的,还有题不会的,数组下标变量搞错的。

以后一定注意:

                       1.认真检查。

                       2.多读几遍题。

                       3.多复习二维数组的行和列。

                       4.以后写完代码要检查检查是否把注释去掉了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值