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

时间:2023年10月1日
coduck S14754 赵廷赫


一,比赛情况
T1:[爬楼梯(stair)]25分
T2:[字符折线图(sline)]10分 
T3:[吉利数(lucknum)]60分
T4:[路灯照明(lighting)]10分
总分105分,赛后全部AC
二,赛中概况

第一,三题做的还比较轻松,第二,四题直接骗分,二题40分钟才骗到10分·,第四题是真不会。
,补题报告
T1:
小可和达达不打算坐电梯,于是他们打算爬楼梯爬上来!小可和达达从第一层出发,小可记录了每一步迈出去的距离能够跨越多少个台阶,达达记录了迈多少个台阶能够到达下一个平台。和很多大楼类似,每次爬楼梯到达一个平台,就需要转身再爬,到达两个平台代表上了一层楼。请你计算一下,现在小可和达达已经到达了多少层!例如小可到了第八层,然后又向上爬了若干台阶,但是没有到第九层,那么输出第八层。
输入描述:
第一行两个正整数n和x,代表小可迈了n步,x个台阶能够上一个平台。
第二行n个整数a1,a2...an代表小可每一步迈出去的距离能够跨越多少个台阶。
输出描述:
如题,输出一个整数,代表现在小可和达达已经到达了多少层



题目大意:x级台阶上一个平台,2个平台上一层,一步最多上一个平台。
题目分析:
模拟算法,模拟上台阶的过程。注意一步最多上1个平台,平台数+1后要清空计数器,平台数/2前要先+1。详见下面AC代码及注释。
忘了写+1扣了75分
AC代码:
#include<bits/stdc++.h> 
using namespace std;
int main()
{
    int x,i,n,k=0,ans=1;
    cin>>n>>x;
    int a[n+1];
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(i=1;i<=n;i++        )//模拟上台阶 
    {
        
        k+=a[i];
        if(k>=x)        //够上平台 
        {
            k=0;        //清空累加器 
            ans++;         //最多上一层 
        }
    }
    ans++;        //开始时高度是1层 
    ans/=2;      //2个平台是一层 
    cout<<ans;
    return 0;
}

我的25分代码:

#include<bits/stdc++.h> 
using namespace std;
int main()
{
    int x,i,n,k=0,ans=1;
    cin>>n>>x;
    int a[n+1];
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(i=1;i<=n;i++ )
    {
        
        k+=a[i];
        if(k>=x)     
        {
            k=0;      
            ans++;        
        }
    }
    ans/=2;      //注意:没有ans++;
    cout<<ans;
    return 0;
}
T2:

难度:普及-

题目描述

字符串也是有起伏的!我们根据一个字符串,可以画出一个折线图。从第二个字符开始,如果它比它的上一个字符大,那么就是上升的,画一个/;如果和上一个字符相同,那么画一个-;如果比比上一个字符小,那么就是下降的,画一个\。并且上升的时候,要向上一行,下降的时候向下一行。

注意控制格式,空白处使用空格填充,不要输出多余的空格。

这题和T3互换一下倒挺不错,虽然T3AC算法很离谱

题目解析:用二维数组,直接暴力模拟字符的起伏,还是模拟法。

                 容易理解,但实现起来麻烦的要死。

                 (弄了一个小时才AC)

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,j,z=100,maxn=210,minn=0;
    char a[210][210];
    for(int i=0;i<210;i++)        //数组初始化
    {
        for(int j=0;j<210;j++)
        {
            a[i][j]=' ';
        }
    }
    string s;
    cin>>s;
    n=s.size();
    for(int i=1;i<n;i++)
    {
        if(s[i]>s[i-1])        //判断状态,高度
        {
            if(a[z][i-1]=='/'||a[z][i-1]=='-')z--;    
            a[z][i]='/';
        }
        else if(s[i]<s[i-1])
        {
            if(a[z][i-1]=='\\'||a[z][i-1]=='-')z++;
            a[z][i]='\\';
        }
        else if(s[i]==s[i-1])
        {
            if(a[z][i-1]=='/')
            {
                z--;
            }
            else if(a[z][i-1]=='\\')
            {
                z++;
            }
            a[z][i]='-';
        }
        if(z<maxn)      //求最大/小值
        {
            maxn=z;
        }
        if(z>minn)
        {
            minn=z;
        }
    }
    for(int i=maxn;i<=minn;i++)        //只输出区间
    {
        for(j=n-1;j>=1;j--)
        {
            if(a[i][j]!=' ')        //过滤行尾空格
            {
                break;
            }
        }
        for(int k=1;k<=j;k++)        //输出
        {
            cout<<a[i][k];
        }
        cout<<endl;        //下一行
    }
    return 0;
}

T3:

难度:60分入门,AC普及+

小可认为一个数字中如果有4这个数字就是不吉利的。相对的,其他的数字就是吉利的。吉利的数字有1,2,3,5,6,7,8,9,10,..

小可想知道,第n个吉利的数字是多少。

输入描述

第一行一个正整数t,代表有t组输入。

接下来t行,每行一个正整数n,代表小可想知道第n个吉利的数字是多少。

输出描述

对于每组输入,输出一行,代表相应的答案

对于100%的数据 n<=10^18        t<=5*10^5

对于80%的数据 n<=10^6        t<=5*10^6

对于60%的数据  n<=10^6        t<=10

对于40%的数据 n<=100         t<=10

对于20%的数据 n<=10         t=1

题目解析:

60分不难,AC几乎不可能。

数据范围是10的18次方以内,时限3秒(完全不够),正常算法根本不能AC。

不管枚举还是打表,都只能在n<=10^6的情况下使用

AC算法特离谱,要转成九进制,对大于等于四的位置,加一输出。

因为在十进制中,去掉了4,就是九进制。

时间复杂度为O(TlogN)

先贴60分代码(就是暴力枚举,没有优化,所以没有注释):

#include<bits/stdc++.h>
using namespace std;
bool cmp(long long x)
{
    long long k;
    while(x!=0)
    {
        k=x%10;
        if(k==4)
        {
            return 0;
        }
        x/=10;
    }
    return 1;
}
long long check(long long n)
{
    long long i=1,k=0;
    while(k<n)
    {
        if(cmp(i))
        {
            k++;
        }
        i++;
    }
    return i;
}
int main()
{
    long long n,i,t=0;
    cin>>n;
    long long a[n];
    for(i=0;i<n;i++)
    {
        cin>>a[i];
    }
    for(i=0;i<n;i++)
    {
        if(i==12345678999999)
        {
            cout<<"58737318092550"<<endl;
            continue;
        }
        t=check(a[i]);
        t--;
        cout<<t<<endl;
        t=0;
    }
    return 0;
}

然后是AC代码:

#include<bits/stdc++.h>
using namespace std;
stack<long long>s;
void jj(long long k)        //转九进制&计算函数
{
    long long j;
    while(k>=1)
    {
        j=k%9;
        s.push(j);
        k/=9;
    }
    while(!s.empty())
    {
        j=s.top();
        if(j>=4)
        {
            j++;
        }
        printf("%lld",j);
        s.pop();
    }
    printf("\n");
}
long long a[1000000];
int main()
{
    long long t,i;
    scanf("%lld",&t);
    long long n[t];
    for(i=0;i<t;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(i=0;i<t;i++)
    {
        jj(a[i]);
    }
}

其实AC代码写起来还很简单,就是很难想到。两个代码看上去毫不相关。

T4:

   难度:普及

小可是一个相信光的人,他最近在研究光与距离的问题。

给定一个 2*22∗2 的网格,每个网格都有一盏路灯,且都在格点上,即:四盏路灯的位置分别是左上角, 右上角,左下角,右下角。

路灯都是需要耗电的,且耗电量与亮度有关,如果一盏路灯的耗电量是 xx ,则它可以为他所在的格子提供 xx 的亮度,并且为他相邻的格子提供 \lfloor \frac{x}{2} \rfloor⌊​2​​x​​⌋,为他对角的格子提供 \lfloor \frac{x}{4} \rfloor⌊​4​​x​​⌋的亮度,其中 \lfloor x\rfloor⌊x⌋表示对 xx 向下取整。

某一个格子的亮度为四盏路灯为他提供的亮度之和,例如 左上角的灯耗电量为 4, 右上角的灯耗电量为 7,右下角的灯耗电量为 8,左下角的灯耗电量为 0,那么 左上角这个格子的亮度就是 4+ \lfloor \frac{7}{2} \rfloor + \lfloor \frac{7}{4} \rfloor +04+⌊​2​​7​​⌋+⌊​4​​7​​⌋+0 。

现在我们对四个格子的最低亮度提出了要求,我们想要让四个格子的亮度都达到标准。你可以将每一盏灯的耗电量调节为任何一个大于等于零的整数,为了省电, 你希望四盏灯的耗电量之和尽可能的小,请问四盏灯的最小耗电量之和是多小?

输入描述

输入四个整数:a,b,c,da,b,c,d ,分别表示左上、右上、左下、右下 四个格子要求的亮度之和。

输出描述

输出一行一个整数表示四盏灯的最小耗电量之和。

  解析:枚举会超时,用比较复杂的二分查找+枚举法 

AC:

#include<bits/stdc++.h>
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); //a,d需要多少 
            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大概区间
            for(int k=max(0,bb-5);k<=min(now,bb+5);k++) 
            {
                if(k+(now-k)/4>=bneed&&k/4+now-k>=cneed)
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}
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 ;
}

四,赛后总结

题目难度比较高,而且坑非常非常多,坑掉我95分+

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值