日期: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有可能是,所以显然不行。
打表虽然是O(T+N),但还是超限(虽然给了3000ms)。
而九进制使用0~8,9个数字,正好和题目中说除去4后的10进制数字数量相等,所以便可以进行以下操作:
把4的数根据题意,都加上一。
然后输出就行了。
这道题代码好写,思路挺难想,望广大读者仔细钻研。
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+ +
+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)/3tips: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的双斜线删掉啊!不能再犯了!!!
五、心得:
这次属实是心态的问题,这次考试给我敲响了一次警钟,下次一定努力,以更加优秀的自己面对每一次测试!
好了,下篇博文见!