はじめに
昨日、Atocoderを久しぶりにやった。C問題まで解くことができてとても嬉しい。成長していることがわかった(たぶん)。明日からテンプレートやりたいし今日で8章終わらせる。
Stocklist
未解決
・i++と++iの違い ←今日はこれ
・演算子オーバーロード
・fmtlib/fmt
・静的メンバ 参照
・nullptr
・enum class
・std::quick_exit
・初期化子
・みえる・みえない
・this
・標準規格と処理系
Atcoder
ABCコンテスト
今回のAtcoderは std::string
を多様した。以前のAtcoderの問題で文字関連の問題のとき苦戦したが今回はなんとか正解することができた。成長を感じると嬉しい。
std::array
今思うと使ってなかったな。急いでたから []
を使ってしまっていた。
A問題
問題文
2個のボタンがあり、大きさはそれぞれ A,Bです。大きさ Xのボタンを押すと、X枚のコインを獲得し、そのボタンの大きさが1 小さくなります。あなたは、いずれかのボタンを押すことを 2 回行います。 同じボタンを 2 回押しても構いません。
最大で何枚のコインを獲得できるでしょうか。
制約
入力は全て整数である。3≤A,B≤20
#include <iostream>
int main(){
int A = 0;
int B = 0;
int wa = 0;
std::cin >> A >> B;
A > B ? wa = A: wa = B;
A > B ? A-- : B--;
A > B ? wa +=A: wa +=B;
std::cout << wa << std::endl;
}
B問題
問題文
東西に N 個の山が連なっており、西の果てには広大な海が広がっています。
各山頂には旅館があり、あなたは海を眺められる旅館を選ぶことにしました。
西から i 番目の山の高さは Hi です。
西から 1 番目の山頂にある旅館からは必ず海を眺めることができます。
西から i (i=2,3,...,N) 番目の山頂にある旅館については、H1≤Hi, H2≤Hi, ..., かつ Hi−1≤Hi のとき、その旅館から海を眺めることができます。
これら N 個の旅館のうち、海を眺められる旅館はいくつあるでしょうか。
制約
入力は全て整数である。1≤N≤20,1≤Hi≤100
#include <iostream>
int main(){
int N = 0;
int H[100];
int takai = 0;
int count= 0;
std::cin >> N;
for(int i = 0; i < N; i++){
std::cin >> H[i];
if(takai <= H[i]){
takai = H[i];
count++;
}
}
std::cout << count << std::endl;
}
C問題
問題文
左右一列に N 枚のタイルが並んでおり、各タイルの初めの色は長さ N の文字列 S で表されます。
左から i 番目のタイルは、S の i 番目の文字が 0 のとき黒色で、1 のとき白色で塗られています。
あなたは、いくつかのタイルを黒色または白色に塗り替えることで、どの隣り合う 2 枚のタイルも異なる色で塗られているようにしたいです。最小で何枚のタイルを塗り替えることで条件を満たすようにできるでしょうか。
制約
1<= |S| <= 10^5
Siは'0'または'1'
#include <iostream>
#include <string>
int main(){
std::string S;
std::string tasi;
int j = 0;
std::cin >> S;
tasi.push_back(S.at(0));
int count = 0;
for(int i =1;i <S.length();i++){
if( tasi.at(j)==S.at(i) ){
count++;
S.at(i) == '1'?tasi.push_back('0'):tasi.push_back('1');
}else{
tasi.push_back(S.at(i));
}
j++;
}
std::cout << count << std::endl;
}
D問題
問題文
N 人の人が左右一列に並んでいます。
0, 1 からなる長さ N の文字列 S と正整数 K が与えられます。
左から i 番目の人は、S の i 文字目が 0 のとき直立し、1 のとき逆立ちしています。
あなたは K 回まで以下の指示を行います。一度も行わなくても構いません。
指示:
1≤l≤r≤N を満たす整数 l,r を選ぶ。左から l,l+1,...,r 番目の人の状態を反転する。すなわち、i=l,l+1,...,r について、左から i 番目の人は直立していれば逆立ちし、逆立ちしていれば直立する。K 回までの指示で、逆立ちした人を連続で最大何人並ばせることができるか求めてください。
制約
N は 1≤N≤10^5 を満たす整数である。Kは 1≤K≤10^5 を満たす整数である。
文字列 S の長さは N である。文字列 S の各文字は 0 または 1 である。
#include <iostream>
#include <string>
int main(){
std::string str;
std::string saki;
int N =0;
int K =0;
int j = 0;
int zero[10000];
int kazu[10000];
int count = 0;
std::cin >> N >>K;
std::cin >> str;
bool maezero = false;
//str.find('0');
//saki.push_back(str.at(0));
//ゼロの場所を探すだけ
for(int i =0;i <str.length();i++){
if(str.at(i)=='0'){//文字列がゼロのとき
//kazu[j] +=1
if(maezero){//前の文字が0だったらbreak
break;
}
zero[j] = i;//文字列の0の前からの順番を示す
maezero = true;
j++;//jを足す。jは0の出現回数
}else{
maezero = false;
count = 0;
}
//}
// std::cout << j << std::endl;
std::cout << str.cbegin() << std::endl;
std::cout << str.find('0') << std::endl;
std::cout << str.find('0') << std::endl;
}
// if( tasi.at(j)==str.at(i) ){
// count++;
// str.at(i) == '1'?tasi.push_back('0'):tasi.push_back('1');
// }else{
// tasi.push_back(str.at(i));
// }
// j++;
まず for
で文字列から 0文字列
がいくつあるのか調べて、そこから合計値を足していけば実装できるのでは?と考えたがだめだった。公式解説を聞いていると、 累積和
や 尺取法
を使って実装していた。やっぱり、D問題の壁はまだまだ高い。
Openflameworks
関数の解読
ofApp.cpp
にコードを追加していけばいいみたい。物理計算できる ofxBOX2D
ライブラリを見つけたので、これを使ってどのような関数なのか調べていくl.
void setup
この関数は、プログラムを実行してから最初に一度だけ呼ばれる関数である。 Box2d
では、クラスの初期化や重力の設定、背景を宣言をしている。
void ofApp::setup(){
// 背景色を黒に
ofBackground(0, 0, 0);
// 円の分割数
ofSetCircleResolution(1024);
// box2d初期化
box2d.init();
// 重力の設定
box2d.setGravity(0, 0.98);
// 地面の設定
box2d.createBounds();
// フレームレート
box2d.setFPS(30);
for(int i = 0; i < CIRCLE_NUM; i++){
// 質量、跳ね返り係数、摩擦係数
circle[i].setPhysics(10.0, 1.0, 0.01);
// 生成する円の中心座標をランダムで設定
float x = ofRandom(0, ofGetWidth());
float y = ofRandom(0, ofGetHeight());
// 円の半径
float radius = ofRandom(10, 50);
// 円をBox2dの空間に追加
circle[i].setup(box2d.getWorld(), x, y, radius);
// ランダムな色設定
randColor[i] = ofColor(ofRandom(255), ofRandom(255), ofRandom(255));
}
box.setPhysics(0, 0.9, 1.5); // 四角の物理パラメータを設定 (重さ、反発係数、摩擦係数)
box.setup(box2d.getWorld(), ofGetWidth() / 3.0, 600, x, 20); // 四角を物理世界に置く(Box2dの世界,座標(x,y),幅,高さ)
}
void update と void draw
これらの関数は、 setup関数
の 呼び出しが終わると、プログラムが終了するまで交互に呼び出される。
void ofApp::update(){
box2d.update();
}
void ofApp::draw(){
for(int i=0; i<CIRCLE_NUM; i++){
// 円の描画色設定
ofSetColor(randColor[i]);
// Box2d空間の円を描画
circle[i].draw();
}
ofSetColor(255, 127, 0);
box.draw(); // 四角の描画
x++;
}
適当に、ブロック崩しにはバーが必要なので書いてみた。けど、動かない。
まぁ遊びはここまでにして、明日からは本格的にクラスを実装してみようと思う。
++i と i++ の違い
++iは、処理が始まる前にをiに1を加算
i++は、処理を終えてからiに1を加算
と認識していているのだが、 for文
の場合だとどのように処理されるのかわからなかった。
調べてみると、私の認識は間違っていないことがわかった、
また、for文の第三引数で使う i++
++i
には違いがないことがわかった。
ロベールのC++
namespace 2
namespaceの変更
悪と言われてきた using name space
について調べる。
#include <iostream>
namespace ABC = std;
using namespace ABC;
int main(){
ABC::cout << "Hello World" << ABC::endl;
cout << "Hello World" << endl;//省略可能
}
このように、名前空間の名前を変えることができる!
さらに読みにくくなりそう...。
namespace3
#include <iostream>
namespace Myprogram{
void show() {
std::cout << "こんちわ" << std::endl;
}
void run() {
show();
}
}
int main(){
Myprogram::run();
}
実行結果
こんちわ
同じ名前空間内の関数を呼ぶなら名前空間の指定なしに呼ぶことができる。
#include <iostream>
void show(){
std::cout << "hello" << std::endl;
}
namespace Myprogram{
void show() {
std::cout << "こんちわ" << std::endl;
}
void run() {
show();
}
}
int main(){
Myprogram::run();
}
こんちわ
識別指定子がないと、同じ名前空間の関数が優先される
終わりに
明日からtemplateに入ります。
おやすみなさい。