CSP-X模拟赛一 孙晨佑补题报告

日期:2023.10.1    时间:9:30~11:30

学号:s09691   姓名:孙晨佑

(大家看完这篇博文可以再看看我的其他的博文吗?求求了!!!)

一、题目分数(好少(气死哦嘞)):

T1【爬楼梯(stairs)】:(Wrong Answer)0

T2【字符折线图(sline)】:(Wrong Answer)30

T3【吉利数(lucknum)】:(Wrong Answer)0

T4【路灯照明(lighting)】:(Wrong Answer)40

总分也就70分,555

二、比赛过程:

第一题:  :Q

第一题自认全对,就是没想到它x表示的是上一个平台所需要的台阶数。。。。。。(题没说清楚)。

第二题: ;)

 第二题当我看了体感之后就发现——怎么这么难啊喂!!!所以当时就想着能做就做,不能做就放弃(但也得仔细想啊喂,不要学我!),做好了爆0的准备,真的没想到得了30分(意料之外)。

第三题: ;(

这题发现和思维题库里的“王国守卫” 挺像的,所以直接用数组存了,但当我看到如此大的数据范围时,我整个人都傻了,就挺无语的。

第四题: :)))))))))))))))))

这题是我思路最清晰 (打暴力,但是时间超限),同时也是我得分最多的一题(40分,但也挺“多”了),本来以为能全对的,有点小失望。

三、做题思路(还是分为4个部分)

第一题:

大意:小可和达达从第一层出发,求小可走完后现在小可和达达已经到达了多少层。

思路:

1、输入。

2、for循环遍历数组并设t等于x,ans=0,分别表示当前还剩几个台阶能上一个平台、上的层数,然后进行计算,注意这里有一个魔鬼细节——eg:当你t=1且a[i]恰好大于t的时候,你不可以一次性跨过多个平台,而是将t清零,ans++后进行下一轮的计算。

3、输出,这里也有个魔鬼细节,那就是x表示的是走一个平台需要的台阶数(上文提到过),所以我们输出的时候要ans/2,又因为1层不用爬,所以还要加一。

AC代码(Wrong Answer代码就不发了,怕误导你们):

#include<iostream>
using namespace std;
int main(){
	int n,x;
	cin>>n>>x;
	int t=x,a[100005],ans=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(t>a[i]) t-=a[i];
		else ans++,t=x;
	}
	cout<<ans/2+1;
	return 0;
} 

第二题:

大意:给一个字符串:从第二个字符开始,如果它比它的上一个字符大,那么就是上升的,画一个/;如果和上一个字符相同,那么画一个-;如果比比上一个字符小,那么就是下降的,画一个\。并且上升的时候,要向上一行,下降的时候向下一行。输出这个折线图。

思路:

这题说又是往下输出又是往上输出,用cin、cout显然超级麻烦(也可能无法实现,因为作者没用cin、cout,完全未知),显而易见可以使用二位字符数组存储(赋初值为' ')。

如果当前要输出'/'那么有三种可能:
1、

前一个是'/',那么行要减一。

2、

前一个是'-',那么行还是要减一。

3、

前一个是'\',那么不用变。

如果当前要输出'-'那么也有三种可能:
1、

前一个是'/',那么行要减一。

2、

前一个是'-',那么不用变。

3、

前一个是'\',那么行要加一。

如果当前要输出'\'那么还是有三种可能:
1、

前一个是'/',那么不用变。

2、

前一个是'-',那么行要加一。

3、

前一个是'\',那么行要加一。

最后存储起来。

总共就这几种可能性 。

让我们举个例子:

hhhhh     ----->     ----

ababa     ---->     /\/\

以此类推。

还要求个行列最大最小值之类的东西(要不然时间超限)。

所以——

上AC 代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int main(){
	char a[205][205];
	memset(a,' ',sizeof a);
	string s;
	cin>>s;
	int l=s.size(),h=100,maxx=0,minn=0x3f3f3f;
	for(int i=1;i<l;i++){
		if(s[i]>s[i-1]){
			if(a[h][i-1]=='/'){
				a[--h][i]='/';
				minn=min(minn,h);
			}
			else if(a[h][i-1]=='-'){
				a[--h][i]='/';
				minn=min(minn,h);
			}
			else{
				a[h][i]='/';
			}
		}
		else if(s[i]<s[i-1]){
			if(a[h][i-1]=='/'){
			    a[h][i]='\\';
			}
			else if(a[h][i-1]=='-'){
				a[++h][i]='\\';
				maxx=max(maxx,h);
			}
			else{
				a[++h][i]='\\';
				maxx=max(maxx,h);
			}
		}else{
			if(a[h][i-1]=='/'){
				a[--h][i]='-';
				minn=min(minn,h);
			}
			else if(a[h][i-1]=='-'){
				a[h][i]='-';
			}
			else{
				a[++h][i]='-';
				maxx=max(maxx,h);
			}
		}
		maxx=max(maxx,h);
		minn=min(minn,h);
	}
	for(int i=minn;i<=maxx;i++){
		int qw=l-1;
		for(int j=qw;j>=1;j--){
			if(a[i][j]!=' '){
				qw=j;
			    break;
			}
		}
		for(int j=1;j<=qw;j++){
			cout<<a[i][j];
		}
		cout<<"\n";
	}
	return 0;
} 

第三题:

大意:小可认为数字中如果有4这个数字就是不吉利的。相对的,其他的数字就是吉利的。求第n个吉利的数字。

思路:

这题既然不能带4的数字是吉利数。

那么就剩下10-1=9(个)数字。

由此——我们可以想到同样使用9个数字来表示数的进制——九进制!!!!!

因为打暴力时间复杂度为O(TN),而N有可能是10^{18},所以显然不行。

打表虽然是O(T+N),但还是超限(虽然给了3000ms)。

而九进制使用0~8,9个数字,正好和题目中说除去4后的10进制数字数量相等,所以便可以进行以下操作:

 把\geq4的数根据题意,都加上一。

然后输出就行了。

这道题代码好写,思路挺难想,望广大读者仔细钻研。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int t;
ll n;
int a[30],cnt;
void print(ll n){
	while(n){
		ll t=n%9;
		n/=9;
		a[++cnt]=t;
	}
	for(ll i=cnt;i>=1;i--){
		if(a[i]>=4) printf("%d",a[i]+1);
		else printf("%d",a[i]);
	}
	printf("\n");
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%lld",&n);
		memset(a,0,sizeof a);
		cnt=0;
		print(n);
	}
	return 0;
} 

第四题:

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

现在我们对四个格子的最低亮度提出了要求,想要让四个格子的亮度都达到标准,四盏灯的最小耗电量之和是多小?

 思路:

这题代码是简单的,但思维超级麻烦,二分最小化答案+超级优化版枚举,非常出人意料,和第三题一样难受,能写出来大框的你已经很不错了,这题……用一个字形容——难!这个题最难的地方还是check()函数了。

具体思路在代码中又非常详细的解释。

如果用abcd来表示左上、右上、左下、右下的亮度的话——

那我们只需要枚举a和d即可,b和c的推导公式如下:

b+c/4=bn,b+c=now
b+c/4=bn -> 4b+c=4bn
4b+c=4bn -> 3b+now=4bn
p=(4bn-now)/3

tips:bn和cn表示的是b和c还需要多少亮度。

接下来讲一下check函数:

check()函数里要包含以下内容:

 枚举左上耗电量 

枚举右上耗电量 

a,d还需要多少 

还有多少可以分配

b还需要多少 

c还需要多少

估算b大概区间

枚举b在 这个近似值附近再枚举

左下提供 +b>=b   左下>=c需要 

所以——

话不多说,上AC代码:

#include<iostream>
using namespace std;
int a,b,c,d;
bool che(int mid){
	for(int i=0;i<=a;i++){//枚举左上耗电量 
		for(int j=0;j<=d;j++){//枚举右上耗电量 
			int n=max(a-i-j/4,d-j-i/4);//a,d还需要多少 
			if((mid-i-j)/2<n) continue; 
			int now=mid-i-j;//还有多少可以分配 
			int bn=max(0,b-i/2-j/2);// b还需要多少 
			int cn=max(0,c-i/2-j/2);// c还需要多少
			int bb=max(0,(bn-now/4)*4/3);// 估算b大概区间 
			//b+c/4=bn,b+c=now
			//b+c/4=bn -> 4b+c=4bn
			//4b+c=4bn -> 3b+now=4bn
			//p=(4bn-now)/3
			for(int k=max(0,bb-5);k<=min(now,bb+5);k++){// 枚举b在 这个近似值附近再枚举 
				if(k+(now-k)/4>=bn&&k/4+now-k>=cn){//左下提供 +b>=b   左下>=c需要 
					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)/2;
		if(che(mid)){
			ans=mid;
			r=mid-1;
		}else l=mid+1;
	}
	cout<<ans;
	return 0;
} 

四、赛后总结:

一:

今天的题有简单的,有难的,有思路清晰的,有思路难的,算法奇特性层出不穷,感觉这题出的真的很好,就是没考多少分(也就比王胤皓少考50分而已)。

二:

以后一定要记得把注释freopen的双斜线删掉啊!不能再犯了!!!

五、心得:

这次属实是心态的问题,这次考试给我敲响了一次警钟,下次一定努力,以更加优秀的自己面对每一次测试!

好了,下篇博文见!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值