日期:2023.10.1 考试时间:9:30---->11:30
学号:S07738 姓名:王胤皓
一、我的题目分数(有点尴尬)
T1爬楼梯(stair):(Wrong Answer)0分
T2字符折线图(sline):(Wrong Answer)50分
T3吉利数(lucknum):(Wrong Answer)40分
T4路灯照明(lighting):(Wrong Answer)30分
二、考试过程:
第一道题:
第一道题爬楼梯我理解错题意了。。。但是只需要给一个变量改一下就对了。(服了)
第二道题:
第二道题字符折线图,这一个题是我考试花费时间最多的一题。我思考了特别久,我测试了许多样例,都对了,但是最后只得了50分
第三题:
我只会求出80%的数据,就是用O()的时间从1遍历到,用数组存不含有4的数字,后边多组测试数据,输入里面的数据,就可以用O(1)时间直接输出;
第四题:
我实在没有什么思路,只能用打暴力的方法偷分,就是用O(),得了30分。
做题思路:
第一道题爬楼梯:
题目简单概括:
小可和达达从第一层出发,每次爬楼梯到达一个平台,就需要转身再爬,到达两个平台代表上了一层楼。如果小可到了第八层,然后又向上爬了若干台阶,但是没有到第九层,那么输出第八层。
思路:
第一步、输入n、x,作用同题目。
第二步、定义ans表示上了几个平台,cnt表示在这一个平台到下一个平台已经爬了的台阶数,在输入a数组的时候,用cnt加上当前走的步数,如果大于等于了每两个平台之间的台阶的数量,就说明又上了一个平台,因为在迈步子的时候,如果迈出去的台阶之后已经到了平台,那么无论能迈多少步,他都只是到了那个平台了,所以ans+1。
3、他问的是第几层,所以是,他一开始是第一层,所以是1+。
旧代码(Wrong Answer【0分】)(因为理解错了):
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main(){
int n,x;
cin>>n>>x;
int linux=x/2;
int a[100005];
int ans=1,cnt=0,sum=0;
for(int i=1; i<=n; i++){
cin>>a[i];
cnt+=a[i];
if(cnt>=linux){
cnt=0;
sum++;
}
linux=x-linux;
}
cout<<sum/2+ans;
return 0;
}
新代码(Accept【100,满分】):
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main(){
int n,x;
cin>>n>>x;
int a[100005];
int cnt=0,sum=0;
for(int i=1; i<=n; i++){
cin>>a[i];
cnt+=a[i];
if(cnt>=x){
cnt=0;
sum++;
}
}
cout<<sum/2+1;
return 0;
}
第二题字符折线图:
题目简单概括:
可以画出一个折线图。从第二个字符开始,如果它比它的上一个字符大,那么就是上升的,画一个 /
;如果和上一个字符相同,那么画一个 -
;如果比比上一个字符小,那么就是下降的,画一个 \
。并且上升的时候,要向上一行,下降的时候向下一行。
空白处使用空格填充,不要输出多余的空格。
思路:
1、输入字符串
2、画图详解:
根据图片
先定义一个height(高度)=100和一个char类型二维数组,并全部赋值为空格
从第2个字符开始遍历字符串,
设当前字符在这个字符串中的位置为i
我们进行分类讨论
如果位置为的字符的ASCLL值大于位置为i-1的字符的ASCLL码值
如果上一个是'/'
height减1,存储
如果上一个是'-'
height减1,存储
如果上一个是'\'
height不变,存储
如果位置为的字符的ASCLL值小于位置为i-1的字符的ASCLL码值
如果上一个是'\'
height+1,存储
如果上一个是'-'
height+1,存储
如果上一个是'/'
height不变,存储
如果位置为的字符的ASCLL值等于位置为i-1的字符的ASCLL码值
如果上一个是'/'
height减1,存储
如果上一个是'-'
height不变,存储
如果上一个是'\'
height+1,存储
(在求的时候,顺便求一下最高和最低)
3、打印矩阵。(tips:需要从最低开始,到最高结束,然后从后面进行遍历,如果检测到了不是空格的字符,那么记下来,然后for循环到记下来的数字,输出)
旧代码(Wrong answer(50分))
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main(){
int flag[105];
string a;
cin>>a;
int len=a.size();
char cc;
cc=a[0];
for(int i=1;i<a.size(); i++){
if(a[i]==cc) flag[i]=1;
else if(a[i]>cc) flag[i]=0;
else flag[i]=2;
cc=a[i];
}
int height[105]={0};
int heightcnt=100;
for(int i=1; i<len; i++){
if(flag[i]==0){
height[i]=heightcnt;
for(int j=i; j>=1; j--){
height[j]++;
}
}
if(flag[i]==2){
height[i]=heightcnt;
heightcnt++;
}
else{
height[i]=heightcnt;
}
}
int begin=0,end=100,flag1=0;
char c[300][300]={' '};
for(int i=0;i<200; i++){
int flagg=0;
for(int j=1; j<len;j++){
if(height[j]==i){
flagg=1;
if(flag[j]==0) c[i][j]='/';
else if(flag[j]==1) c[i][j]='-';
else c[i][j]='\\';
}
}
if(flagg==1&&flag1==0){
flag1=1;
begin=i;
}
if(flagg==0&&flag1==1){
end=i;
break;
}
}
for(int i=begin; i<=end; i++){
for(int j=1; j<len; j++){
cout<<c[i][j];
}
cout<<endl;
}
return 0;
}
新代码(Accept【100,满分】)
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main(){
string a;
cin>>a;
int len=a.size();
char c[222][222];
memset(c,' ',sizeof c);
int hhh=100,maxx=0,minn=400;
for(int i=1; i<len; i++){
if(a[i]>a[i-1]){
if(c[hhh][i-1]!='\\'){
hhh--;
}
c[hhh][i]='/';
}
if(a[i]<a[i-1]){
if(c[hhh][i-1]!='/'){
hhh++;
}
c[hhh][i]='\\';
}
if(a[i]==a[i-1]){
if(c[hhh][i-1]=='\\') hhh++;
else if(c[hhh][i-1]=='/') hhh--;
c[hhh][i]='-';
}
maxx=max(maxx,hhh);
minn=min(minn,hhh);
}
for(int i=minn; i<=maxx; i++){
int len2=len-1;
for(int j=len-1; j>0; j--){
if(c[i][j]!=' '){
len2=j;
break;
}
}
for(int j=1;j<=len2; j++){
cout<<c[i][j];
}
cout<<endl;
}
return 0;
}
第三题吉利数:
题目简单描述:
小可认为一个数字中如果有4这个数字就是不吉利的。相对的,其他的数字就是吉利的。吉利的数字有1,2,3,5,6,7,8,9,10,..
小可想知道,第n个吉利的数字是多少。
思路:
将十进制转换为九进制,对于数字中大于等于4的位置,加一输出即可。
因为相当于在十进制中,去掉了4这个数字,那么就是九进制。
旧代码(Wrong Answer(40分)):
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int a[5000005];
int main(){
long long ans=0;
for(int i=1; i<=5000009; i++){
ans++;
while(ans%10==4||ans/10%10==4||ans/100%10==4||ans/1000%10==4||ans/10000%10==4||ans/100000%10==4){
ans++;
}
a[i]=ans;
}
long long t;
scanf("%lld",&t);
while(t--){
long long n;
scanf("%lld",&n);
if(n>=5000009){
cout<<58737318092550<<endl;
continue;
}
printf("%d\n",a[n]);
}
return 0;
}
新代码(Accept【100,满分】):
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main(){
long long t;
scanf("%lld",&t);
while(t--){
long long n;
scanf("%lld",&n);
stack<int> sa;
while(n){
int temp=n%9;
n/=9;
if(temp>=4){
temp++;
}
sa.push(temp);
}
while(sa.empty()!=1){
printf("%d",sa.top());
sa.pop();
}
printf("\n");
}
return 0;
}
第四题路灯照明 :
题目简单描述:
给定一个 2∗2 的网格,每个网格都有一盏路灯,且都在格点上,即:四盏路灯的位置分别是左上角, 右上角,左下角,右下角。
路灯都是需要耗电的,且耗电量与亮度有关,如果一盏路灯的耗电量是 x ,则它可以为他所在的格子提供 x 的亮度,并且为他相邻的格子提供 ,为他对角的格子提供的亮度,其中 表示对 x 向下取整。
某一个格子的亮度为四盏路灯为他提供的亮度之和,例如 左上角的灯耗电量为 4, 右上角的灯耗电量为 7,右下角的灯耗电量为 8,左下角的灯耗电量为 0,那么 左上角这个格子的亮度就是 4+ +0 。
现在我们对四个格子的最低亮度提出了要求,我们想要让四个格子的亮度都达到标准。你可以将每一盏灯的耗电量调节为任何一个大于等于零的整数,为了省电, 你希望四盏灯的耗电量之和尽可能的小,请问四盏灯的最小耗电量之和是多小?
思路:
这段代码是比较难的,想到做法和思路超级难,并且运用的方法更让人出乎意料。这道题正确的做法是二分答案(最小化答案)算法+(超级优化版)枚举算法,非常让人出乎意料。
首先,我们要输如a、b、c、d。
然后,打上二分答案(最小化答案)的代码框架,接下来就要编写最最最难得地方,check()函数!
check函数里面:
要包含这些:
枚举左上亮度
枚举右下
a,d还有多少
还有多少可以分配
b还需要多少
c还需要多少
估算b的大概区间
b+c/4=bneed,b+c=now
b+c/4=bneed->得4b+c=4bneed
4b-c-4bneed -> 3b+now=4bneed
b=(4bneed-now)/4
枚举b在这个近似值附近在枚举
左下提供+b>=b需要 左下>=c需要
每次只要check(mid,a,b,c,d)=true,就用一个变量ans=mid
最后输出ans即可
旧代码(Wrong Answer(30分)):
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main(){
int a,b,c,d;
cin>>a>>b>>c>>d;
int minn=0x3f3f3f3f;
for(int i=0;i<=a;i++){
for(int j=0;j<=b; j++){
for(int k=0;k<=c; k++){
for(int t=0; t<=d; t++){
int ans1=i+(j/2)+(k/2)+(t/4);
int ans2=j+(i/2)+(k/4)+t/2;
int ans3=k+(i/2)+t/2+j/4;
int ans4=t+i/4+j/2+k/2;
if(ans1>=a&&ans2>=b&&ans3>=c&&ans4>=d){
if(minn>i+j+k+t){
minn=min(minn,i+j+k+t);
}
}
}
}
}
}
cout<<minn;
return 0;
}
新代码(Accept【100,满分】):
#include<iostream>
#include<iomanip>
#include<map>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
bool check(int mid,int a,int b,int c,int d){
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,(bneed-now/4)*4/3);//估算b的大概区间
//b+c/4=bneed,b+c=now
//b+c/4=bneed->得4b+c=4bneed
//4b-c-4bneed -> 3b+now=4bneed
//b=(4bneed-now)/4
for(int k=max(0,bb-5);k<=min(now,bb+5);k++)//枚举b在这个近似值附近在枚举
if(k+(now-k)/4>=bneed&&k/4+now-k>=cneed)//左下提供+b>=b需要 左下>=c需要
return true;
}
}
return false;
}
int main(){
int a,b,c,d;
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,a,b,c,d)) ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans;
return 0;
}
赛后总结
总结一:今天的题有点难
总结二:真正代码用的算法出乎意料
总结三:(专门写给某些人)考试的时候freopen和fclose记得写对,记得保存,记得保存的时候去掉注释着freopen和fclose的注释。