2022年11月10日木曜日

出力形式に関する問題

小数の出力形式

ABC274-A

問題概要

A/Bを小数第4位で四捨五入した値を末尾ゼロを省略せずに表記して出力せよ。

解答

a,b=gets.chomp.split(" ").map(&:to_i)
printf("%.3f\n", (b.to_f/a).round(3))
    

aかbのどちらかを小数に変換して割り算し、そのオブジェクトからroundメソッド呼び出して引数に表示したい小数点以下の桁数を渡す。

あとはprintfが0埋めをやってくれる。

どうということのない問題なのだが、実際には改めて調べなおしてやることになった。

上が本番の提出コード。Cでやったのが以下。

int readint(char *s);
#include<stdio.h>
#include<stdlib.h>
#define N1 7
int main(void){
    char* s1=(char*)malloc(sizeof(char)*N1);
    if(s1==NULL){
        printf("memory allocation to s1 failed\n");
        exit(1);
    }
    fgets(s1,N1,stdin);
    int a=readint(s1);
    int j=0;
    while(*(s1+j)!=32)j++;
    j++;
    int b=readint(s1+j);
    free(s1);
//    printf("a=%d, b=%d\n",a,b);
    int quot10000=b*10000/a;
//    printf("quot10000=%d\n",quot10000);
    int arr[5];
    for(int i=0,divisor=10000;i<5,divisor>0;divisor/=10,i++){
        arr[i]=quot10000/divisor;
        quot10000-=arr[i]*divisor;
//        printf("arr[%d]=%d\n",i,arr[i]);
    }
    char str[6];
    str[0]=arr[0]+48;
    str[1]=46;
    str[2]=arr[1]+48;    
    str[3]=arr[2]+48;
    if (arr[4]<5){
        str[4]=arr[3]+48;
    }else{
        str[4]=arr[3]+1+48;
    }
    str[5]=0;
    printf("%s\n",str);
    return 0;
}
int readint(char *s){
    int i=0,ret=0;
    while(*(s+i)>=48 && *(s+i)<=57){
        ret*=10;
        ret+=*(s+i)-48;
        i+=1;
    }
    return ret;
}
    

16進数に変換し、先頭に0埋め

ABC271-A

問題概要

10進法で表された整数nが与えられる。(1≦n≦255) nを二桁の16進数として出力せよ。ただし、二桁未満になる時は、先頭に0を埋める。

解答

n=gets.to_i
s=[]
q,x=n.divmod(16)
h={0=>"0",1=>"1",2=>"2",3=>"3",4=>"4",5=>"5",6=>"6",7=>"7",8=>"8",9=>"9",10=>"A",11=>"B",12=>"C",13=>"D",14=>"E",15=>"F"}
s.push(h[q])
s.push(h[x])
puts s.join("")
    

これが本番の提出コード。

0から15の数字をキー、"0"から"F"までの文字を値とするハッシュを作り、与えられた数字を16で割った商をキーとする値を16の位に、余りをキーとする値を1の位に入れている。

もっとも、rubyにはもともと10進数を16進数に変換する機能が備わっているので、以下のようにそちらを利用してもよい。

n=gets.to_i
nn=sprintf("%02X",n)
puts nn
    

本番でこれを使わなかったのは、これだと先頭に0xが入ると思い込んでいたからなのだが、やってみたら0x無しで出力できた。

Cでやったのが以下。

char convert_to_hexadeca_1(int n);
int readint(char *s);
#include<stdio.h>
#include<stdlib.h>
#define N1 5
int main(void){
    char* s1=(char*)malloc(sizeof(char)*N1);
    if(s1==NULL){
        printf("memory allocation to s1 failed\n");
        exit(1);
    }
    fgets(s1,N1,stdin);
    int n=readint(s1);
//    printf("n=%d\n",n);
    int n1=n/16;
    int n2=n%16;
//    printf("s0=%d, s1=%d\n",n1,n2);
    char str[3];
    str[0]=convert_to_hexadeca_1(n1);
    str[1]=convert_to_hexadeca_1(n2);
    str[2]=0;
    printf("%s\n",str);
    return 0;
}
int readint(char *s){
    int i=0,ret=0;
    while(*(s+i)>=48 && *(s+i)<=57){
        ret*=10;
        ret+=*(s+i)-48;
        i+=1;
    }
    return ret;
}
char convert_to_hexadeca_1(int n){
    if (n>=16){
        printf("n must be less than 16.\n");
        exit(1);
    }
    if (n<0){
        printf("n must not be negative.\n");
        exit(1);
    }
    char c;
    if (n>=0 && n<10){
        c=n+48;
    }else if (n>9 && n<16){
        c=n-10+65;
    }
    return c;
}
    

時刻の表示

ABC258-A

問題概要

21時からk分後の時刻をhh:mmの形で出力せよ。

解答

n=gets.to_i
m=s=0
m,s=n.divmod(60)
m+=21
printf("%02d:%02d\n",m,s)
    

上が本番の提出コード。Cでやったのが以下。

int readint(char *s);
#include<stdio.h>
#include<stdlib.h>
#define N1 5
int main(void){
    char* s1=(char*)malloc(sizeof(char)*N1);
    if (s1==NULL){
        printf("memory allocation to s1 failed.\n");
        exit(1);
    }
    fgets(s1,N1,stdin);
    int k=readint(s1);
//    printf("k=%d\n",k);
    int hour=21+k/60;
    int minute=k%60;
//    printf("hour=%d, minute=%d\n",hour,minute);
    char str[6];
    str[0]=hour/10+48;
    str[1]=hour%10+48;
    str[2]=58;
    str[3]=minute/10+48;
    str[4]=minute%10+48;
    str[5]=0;
    printf("%s\n",str);
    return 0;
}
int readint(char *s){
    int i=0,ret=0;
    while(*(s+i)>=48 && *(s+i)<=57){
        ret*=10;
        ret+=*(s+i)-48;
        i+=1;
    }
    return ret;
}
    

先頭0埋め

ABC254-A

問題概要

3桁以上の整数が与えられる。その下2桁を、xxの形で出力せよ。

解答

n=gets.to_i
t1=(n%10).to_s
n/=10
ans=(n%10).to_s
ans+=t1
puts ans    
    

上が本番の提出コード。

1の位の数と10の位の数をいったん文字列にしてから連結している。

後になって考えると、次のようにした方が簡単だったのだが。

n=gets.to_i
printf("%02d\n",n%100)
    

Cでやったのが以下。

int readint(char *s);
#include<stdio.h>
#include<stdlib.h>
#define N1 5
int main(void){
    char* s1=(char*)malloc(sizeof(char)*N1);
    if (s1==NULL){
        printf("memory allocation to s1 failed.\n");
        exit(1);
    }
    fgets(s1,N1,stdin);
    int n=readint(s1);
//    printf("n=%d\n",n);
    int n10=(n/10)%10;
    int n1=n%10;
//    printf("n10=%d, n1=%d\n",n10,n1);
    char str[3];
    str[0]=n10+48;
    str[1]=n1+48;
    str[2]=0;
    printf("%s\n",str);
    return 0;
}
int readint(char *s){
    int i=0,ret=0;
    while(*(s+i)>=48 && *(s+i)<=57){
        ret*=10;
        ret+=*(s+i)-48;
        i+=1;
    }
    return ret;
}    
    

切り捨て

ABC314-A

問題概要

3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679の小数第n位以下を切り捨てて出力せよ。

解答

最初、問題を、「小数第n+1位で四捨五入せよ」というものだと勘違いしてしまって書いたのが次のコード

n=gets.to_i
s="3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
ans=""
t=s[n+2].to_i
if t>=5
    ss=s[n+1].to_i
    ss+=1
    if ss==10
        s[n+1]="0"
        sss=s[n].to_i+1
        if sss==10
            s[n]="0"
            s[n-1]=(s[n-1].to_i+1).to_s
        else
            s[n].sss.to_s
        end
    else
        s[n+1]=ss.to_s
    end
end
(2+n).times do |i|
    ans[i]=s[i]
end
puts ans
    

9が最大で何個まで続いているか分からなければまた別の処理が必要になるが、この問題の文字列では9は2つまでしか連続していないから、これで十分。なぜかWAがいくつか出るので、いったん放棄していたのだが、B問題をやったあと改めて見直してみて問題の勘違いに気付いた。それで書き直したのが以下。

n=gets.to_i
s="3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
ans=""
t=s[n+2].to_i
(2+n).times do |i|
    ans[i]=s[i]
end
puts ans
    

これでACになった。有り得ないような勘違いだったのだが、まさか単なる切り捨てのような簡単すぎる問題は出ないだろうという思い込みで問題文を読み違えてしまったようだ。

Cでやったのが以下。

int readint(char *s);
#include<stdio.h>
#include<stdlib.h>
#define N1 5
int main(void){
    char* s1=(char*)malloc(sizeof(char)*N1);
    if (s1==NULL){
        printf("memory allocation to s1 failed.\n");
        exit(1);
    }
    fgets(s1,N1,stdin);
    int n=readint(s1);
//    printf("n=%d\n",n);
    char pi[]="3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
    char str[103];
    str[0]=pi[0];
    str[1]=pi[1];
    for(int i=1;i<=n;i++){
        str[i+1]=pi[i+1];
    }
    str[n+2]=0;
    printf("%s\n",str);
    return 0;
}
int readint(char *s){
    int i=0,ret=0;
    while(*(s+i)>=48 && *(s+i)<=57){
        ret*=10;
        ret+=*(s+i)-48;
        i+=1;
    }
    return ret;
}
    

0 件のコメント:

コメントを投稿