こんにちはRockinWoolです。最近は結構頑張って活動できていると思います。頭痛も寒さに慣れたからか軽減できていますしね。
さて、1週間前の話になりますがABC#336を解いてみたので、解説と比較していこうと思います。今回は45分で3問も解けたので自分を褒めたい一方で、4問目で完全にスタックしたので解法を確認していこうと思います。それでは。

A問題 龍文字列

なんのことは無い平凡なA問題です。oをN個付ければ良いだけなのでかんたんでした。

#include<iostream>
#include<string>
using namespace std;

int main(){
    int N;
    cin >> N ;
    cout<<'L';
    for(int i=0;i<N;i++){
        cout<<'o';
    }
    cout<<"ng"<<endl;
}

B問題 CTZ

2進数化した時に、末尾に何個0が連続するかを算出する問題です。一般的に使われるc++のライブラリではstring型で出てこないため0の個数を確認することができませんでした。そこで、自作でstring型の2進数を返すtoBinaryを作ってやれば解決します。

#include <iostream>
#include <bitset>
using namespace std;

string toBinary(int n) {
  string r;
  while (n != 0) {
    r += (n % 2 == 0 ? "0" : "1");
    n /= 2;
  }
  return r;
}

int main(void){
	long long N;
	cin >> N;

    string BI;
	BI = toBinary(N);
    int ctx=0;
	for(int i=0;i<BI.size();i++){
        if(BI[i]=='0'){
            ctx +=1;
        }
        else{
            break;
        }
    }
    cout<<ctx<<endl;
    return 0;
}

ちなみに公式ではbitsライブラリを使って下記のように解いていました。

#include <bits/stdc++.h>
using namespace std;
int main() {
	int n;
	cin>>n;
	for(int i=0;;i++){
		if(n&(1<<i)){
			cout<<i<<endl;
			return 0;
		}
	}
}

まずint nがbitとして扱えることに驚き、次に1を左にi個シフトするのを1<<iと表現するのがびっくりですね。あとは、左にi桁シフトした1とnでandを取って0でなければ0がi個あることになるという仕組みです。1<<iの挙動に関しては下記プログラムで確認しました。

#include<iostream>
#include<string>
using namespace std;

int main(){
    int n;
    cin >> n;
    n = 1<<n;
    cout << n <<endl;
}

これだとn=3で8, n=2で4, n=1で2, n=0で1を出力します。左にn個シフトしていることがわかりますね。

C問題 EvenDigits

5個の数字{0,2,4,6,8}のみを使って低い順に並べて、i番目に低い数字を答えるという問題。これは{0,1,2,3,4}だったとしたら5進数を答えれば良いと気づけたので、B問題のtoBinaryを流用して5進数を算出する関数を作ればクリアです。

#include <iostream>
#include <unordered_map>
#include <string>

using namespace std;
// 7を入力すると21と変換されるように、実際とは逆順になる
string to5inary(long long n) {
  string r;
  if(n==0){return "0";}
  while (n != 0) {
    if(n%5 ==0){
        r +="0";
    }else if(n%5 ==1){
        r +="2";
    }else if(n%5 ==2){
        r +="4";
    }else if(n%5 ==3){
        r +="6";
    }else{
        r +="8";
    }
    n /= 5;
  }
  return r;
}


int main(){
    long long N;
    string Fifnary;
    cin >> N;
    Fifnary = to5inary(N-1);
    for(int i=Fifnary.size()-1;i>=0;i--){
        cout << Fifnary[i];
    }
    cout <<endl;
}

コードの質と量は全然違いますが、公式でもまったく同じ解き方をしていたので嬉しいですね。公式から学べることとしては、for(int i=Fifnary.size()-1;i>=0;i–)の部分をreverse(Fifnary.begin(),Fifnary.end())と書けたということでしょうか。

D問題 ピラミッド数列

ピラミッド数列を考えるときにまず困ったのは1,1,2,2,3,2,2,1のように、もともとの数列の中心を軸にピラミッドを作ると121が算出されるけれど、本当の最大ピラミッドは12321のパターンです。結局これが解けなかったのでこの問題でスタックしました。
さて、公式の回答をここで見てみましょう。

#include <bits/stdc++.h>
using namespace std;
int main(void){
	int n,ans=0;
	cin>>n;
	vector<int>a(n+2);
	vector<int>m1(n);
	vector<int>m2(n);
	for(int i=0;i<n;i++)cin>>a[i+1];
	m1[0]=min(a[0],a[1]-1);
	for(int i=1;i<n;i++)m1[i]=min(m1[i-1],a[i+1]-i-1);
	m2[n-1]=a[n+1]+n+1;
	for(int i=n-2;i>=0;i--)m2[i]=min(m2[i+1],a[i+2]+i+2);
	for(int i=0;i<n;i++)ans=max(ans,min(m1[i]+i+1,m2[i]-i-1));
	
	cout<<ans<<endl;
	return 0;
}

解説を読んだのですが、かなり複雑で難しいです。解説を写経してなんとか意味はわかったのですが、これを時間内に解くとなるとなにかが必要ですね。

まとめ

D問題に初めて挑戦してみましたが、かなり難しいですね。これからも精進していつかは解けるようになりたいものです。それではまた次回!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です