ebisukeプログラミング初心者脱出黙示録

30歳を過ぎてから始めたプログラミングと競プロの記録。Pythonで取り組んでいます。Arduinoで電子工作も

AtCoder-ABC217 C - Inverse of Permutation【Python解答例】

AtCoder Beginner Contest217のC問題についてPythonの解答例を記事にしていきます。
AtCoder Beginner Contest 217 - AtCoder


AtCoder Beginner Contest217 C - Inverse of Permutation

C - Inverse of Permutation

問題文

1,2,…,N が 1 回ずつ現れる長さ N の数列を「長さ N の順列」と呼びます。
長さ N の順列 P=(p 1​ ,p 2​ ,…,p N​ ) が与えられるので、以下の条件を満たす長さ N の順列 Q=(q 1​ ,…,q N​ ) を出力してください。

・全ての i (1≤i≤N) に対して Q の p i​ 番目の要素が i である。
ただし、条件を満たす Q は必ずただ 1 つ存在することが証明できます。

制約

・1≤N≤2×10 ^5
・(p 1​ ,p 2​ ,…,p N​ ) は長さ N の順列である。
・入力は全て整数である。

解答例

n = int(input())

P = list(map(int, input().split()))

Q = [0] * n

for i in range(n):
    Q[P[i]-1] = i+1

print(*Q)

解説

問題文のように処理するため長さNで要素が0で初期化された配列Qを用意します。

QをP[i]番目の要素がiである配列としたいので、Q[P[i]-1] = i+1という処理をN個の要素に対して行います。

配列のインデックスは0からはじまるので注意が必要です。

最後にQの各要素を空白区切で出力すればOKでした。
(この出力の仕方は便利なのですぐに思い出せるようにしたいです)



ABC217の関連記事はこちら
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com

AtCoder-ABC217 A - Lexicographic Order / B - AtCoder Quiz【Python解答例】

AtCoder Beginner Contest217のA とB問題についてPythonの解答例を記事にしていきます。
AtCoder Beginner Contest 217 - AtCoder



AtCoder Beginner Contest217 A - Lexicographic Order

A - Lexicographic Order

問題文

相異なる二つの文字列 S,T が与えられます。
S が T よりも辞書順で小さい場合は Yes を、大きい場合は No を出力してください。

制約

・S,T は英小文字からなる長さ 1 以上 10 以下の相異なる文字列である。

解答例

s, t = input().split()

if s < t:
    print("Yes")
else:
    print("No")

解説

2つの文字列SとTが与えられ、SがTより辞書順で小さいか大きいかを答える問題です。

Pythonでは比較演算子を使用することで簡単に辞書順比較ができます。

if s < t:の部分でsとtを辞書順比較し、その結果に合わせて解答すればOKです。



AtCoder Beginner Contest217 B - AtCoder Quiz

B - AtCoder Quiz

問題文

AtCoder では現在、 ABC , ARC , AGC , AHC の 4 つのコンテストが定期的に開催されています。

AtCoder で現在定期的に開催されているコンテストは S 1​ , S 2​ , S 3​ とあと 1 つは何ですか?

制約

・S 1​ , S 2​ , S 3​ はそれぞれ、 ABC , ARC , AGC , AHC のいずれかである。
・S 1​ , S 2​ , S 3​ は相異なる。

解答例

s = []
for i in range(3):
    s.append(input())

if "ABC" not in s:
    print("ABC")
elif "ARC" not in s:
    print("ARC")
elif "AGC" not in s:
    print("AGC")
else:
    print("AHC")

解説

開催されている4つのコンテストのうち、S1,S2,S3に含まれていないコンテストを答える問題です。

S1からS3を配列にいれて、それぞれABCから配列に含まれているかを順番に確かめていきました。

ふくまれていないコンテストがあれば、そのコンテストを出力すればACでした。





ABC217の関連記事はこちら
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com

初心者のArduinoプログラミング入門【サーボモータ編】

今回もArduinoでプログラミング学習をしていきます!

この記事ではサーボモータの基本的な使い方を学習します。

可変抵抗を使用してサーボモータの回転角度を制御することが目標です。

サーボモータとは

一般的なDCモータは電流を流すとくるくる回りつづけますが、サーボモータは軸の角度を制御できるモータです。

今回は安価なSG-90というサーボモータを使います。

目標

ブレッドボード、可変抵抗とサーボモータを使用して回路を作ります。

可変抵抗にあわせてサーボモータの軸を回転させることを目標としました!

回路図

f:id:ebisuke33:20210903221313p:plain

アナログ入力端子A0を可変抵抗に、デジタル3番ピンをサーボモータに接続しました。

SG-90ではモータの茶色の線をGND、赤色を5V、オレンジを制御するピンに接続します。

f:id:ebisuke33:20210903221356p:plain

上図のような回路図になります。

スケッチ

// サーボモータを動かすためのライブラリ
#include <Servo.h>

// サーボオブジェクトの宣言
Servo myServo;

void setup() {
  pinMode(3, OUTPUT);
  // サーボを接続したピン番号3を入力
  myServo.attach(3);
}

void loop() {
  int v = analogRead(0);
  // アナログ入力を0~180に変換
  v = map(v, 0, 1023, 0, 180);
  // サーボの角度を指定
  myServo.write(v);
  delay(10);
}

まずServoライブラリのインクルードを行い、サーボモータを使える状態にします。

「スケッチ」タブから「ライブラリをインクルード」→「Servo」の順で選択しました。

Servo myServoの部分でServoオブジェクトの宣言を行い、myServoがサーボモータだと決定させます。

myServo.attach(3)ではサーボモータと接続したデジタルピンの番号を書きます。

サーボモータを使用するときはPWM(~マークのある)ピンでなければならないので、ここでは3番ピンと接続しています。


アナログ端子からの入力vは最初0~1023の範囲内の整数ですが、回転角度0~180°に変換したいのでmap関数を使って変換しました。

その角度vを myServo.write(v)とすることでサーボモータの軸角度がvになるよう動作するはず!です。

動作確認


www.youtube.com

可変抵抗のつまみの回し方にあわせてサーボモータの軸を回転させることができました!

つまみの回す速さにも連動しています。

まとめ

今回は基本的なサーボモータの使い方を練習しました。

0~180°の間で好きな角度で指定してモータを回すことができるのでいろいろな電子工作に応用できますね!




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門【シリアルモニタ編】

今回もArduinoでプログラミング学習をしていきます!

この記事ではアナログ入力とシリアルモニタの基本的な使い方を学習します。

可変抵抗を使用してアナログ入力端子に加わる電圧の変化をシリアルモニタで観察することが目標です。

目標

ブレッドボード、可変抵抗とボタンスイッチを使用して回路を作ります。

ボタンスイッチが押されているときに、可変抵抗により変化するアナログ入力端子の電圧をシリアルモニタでPCに表示させることを目標としました!

回路図

f:id:ebisuke33:20210901220640j:plain

アナログ入力端子A0を可変抵抗に、デジタル7番ピンをボタンスイッチに接続します。


f:id:ebisuke33:20210901220800j:plain

上図のような回路図になります。

アナログ入力端子の分解能

Arduino UNOのアナログ入力端子の分解能は10bitです。

したがって2^10 = 1024段階の数値(0~1023)でArduinoは認識することができます。

この値を用いてサーボモータの回転角度を指示することもできるので、機会があったら試してみたいと思います。


アナログ入力値はanalogRead関数で読み取ることができます。

次のスケッチでさっそく使ってみます。

スケッチ

// ピン7をボタンスイッチに割り付け
const int pinButton = 7;

void setup() {
  // シリアル通信の設定
  Serial.begin(9600);
  // ピン7をにPULLUPして入力に
  pinMode(pinButton, INPUT_PULLUP);
}

void loop() {
  // アナログ0番ピンの値をaに代入
  int a = analogRead(0);
  
  // ボタンが押されていたら
  if (digitalRead(pinButton) == LOW){
    // アナログ0番ピンの値を出力
    Serial.println(a);
  }
  delay(500);
}

ボタンスイッチはデジタル7番ピンに割り付けます。

シリアルモニタを有効にするため、setup()内でSerial.begin(9600)によりシリアル通信の準備を行います。

(9600)は通信速度で、シリアルモニタ画面の設定と同じにする必要があります。


loop()内ではアナログ0番ピンの値をanalogRead関数で読み取り、aに代入しました。

ボタンスイッチが押されているときにSerial.println関数でシリアルモニタにaを出力します。


これでシリアルモニタにaの値が表示されますので、その値を確認していきました。

動作確認

シリアルモニタはツールタブからシリアルモニタの項目をクリックすると表示できます。
右上にある虫眼鏡ボタンを押すことでも、同じ画面を開けます。

f:id:ebisuke33:20210901220946p:plain


ブレットボード中央左にあるボタンを押すと、シリアルモニタに値が表示されました。

f:id:ebisuke33:20210901221018j:plain


さらにブレットボード中央右にある可変抵抗のツマミを回すと、表示される値が変化することが確認できました。

f:id:ebisuke33:20210901221058p:plain

まとめ

可変抵抗に加わる電圧をアナログ入力端子で取り込むこと、そして、取り込んだ値をシリアルモニタでパソコンに表示することを学びました。

Arduinoデバッグ時に有効だと思いますので、これからも活用して使いこなせるようになりたいです。



この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門【LEDの明るさ制御編】

今回もArduino UNOでプログラミング学習をしていきたいと思います。



この記事ではLEDを使用して、時間とともにLEDの明るさを変化させることが目標です。

目標

ブレッドボードと抵抗(1kΩ)、LEDを使って回路を作成します。

時間がたつにつれて、徐々にLEDが明るくなり、最も明るくなるとぱっと消える制御が目標です。

回路図

f:id:ebisuke33:20210901215834j:plain

今回、アナログ出力で明るさを制御するつもりです。

そのため~マークがついているピンを選ぶ必要があり、9ピンを選びました。


f:id:ebisuke33:20210901215855j:plain

ピン9とLEDを、LEDの反対側は1kΩの抵抗を通じてGNDに接続しています。

スケッチ

// ピン9をLEDに割り付け
const int pinLed = 9;

void setup() {
  // ピン9を出力に
  pinMode(pinLed, OUTPUT);

}

void loop() {
  // iを0~255までループさせる
  for(int i=0; i<256; i++){
    // iの値によって明るさを設定
    analogWrite(pinLed,i);
    // 20msec待つ
    delay(20);
  }

}

9番ピンをLEDの出力に設定します。

analogWrite関数でピンにかかる電圧をアナログ的に制御しました。

i = 0のときは0Vで、i = 255のとき5V出力されます。

for文によってiを0から255まで20msecごとに設定することで、LEDの明るさが周期的に変わるはず!です。

動作確認

時間がたつと徐々にLEDの明るさが変わりました!

明るくなるとぱっと消えて、また明るくなっています。


www.youtube.com

まとめ

アナログ出力を使ってLEDの明るさを制御する目標を達成できました。

単純なONやOFFだけでなく微妙な加減を行うことがおもしろかったです!




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門【ボタンスイッチ編】

Arduinoでプログラミング学習をしていきたいと思います。


この記事ではボタンスイッチとLEDを使用して、ボタンを押したときにLEDを点灯させることが目標です。


目標

ブレッドボードにボタンスイッチとLEDを使って回路を作ります。

先に記載したようにボタンを押すとLEDが光るような制御を行うことが目標です。

回路図

f:id:ebisuke33:20210901214512j:plain

今回はブレッドボード、ボタンスイッチ、LEDと抵抗を使用して回路を作成します。


f:id:ebisuke33:20210901214519p:plain

回路図のようにボタンスイッチは片側をGND、もう一方をピン3に接続します。

LEDも片側をGND、もう一方は220Ωの抵抗を通じてピン7に接続しました。

スケッチ

//ピン3にボタンスイッチ割り付け
const int pinButton = 3;
//ピン7にLEDを割り付け
const int pinLed = 7;

void setup() {
  //ピン3(pinButton)を入力(High)に設定
  pinMode(pinButton, INPUT_PULLUP);
  //ピン7(pinLed)を出力に設定
  pinMode(pinLed, OUTPUT);

}

void loop() {
  //ボタンスイッチ(pinButton)が押されず、HIGHなら{}内の処置を行う
  if (digitalRead(pinButton) == HIGH ){
  //LEDをLOWにする(消灯)
  digitalWrite(pinLed, LOW);
  }
  //それ以外(ボタンスイッチが押されている)なら
  else {
  //LEDをHIGHにする(点灯)
  digitalWrite(pinLed, HIGH);  
  }
}

スケッチの最初では、ボタンスイッチと接続したピン3をpinButtonに、LEDと接続したピン7をpinLedという名前にしています。

これにより、このスケッチ内ではボタンスイッチについて操作を行う場合はpinButton、LEDを操作するときはpinLedと書くことでそれぞれ操作できるようになりました。

次に各ピンの初期設定を行います。

ボタンスイッチが割り付けられているピン3は入力としています。

ボタンスイッチはGNDに接続しているので、押されていないときはHIGHとしておき、ボタンが押されたときはLOW(GND)になるようにPULLUPしています。

LEDが接続されているピン7は出力に設定しています。


loop内ではボタンが押されているかどうかを判定しています。

ボタンスイッチが押されていなければpinButtonはHIGHなので、LEDが接続されているピン7はLOWとなります。したがって電流は流れず、LEDは点灯しません。

ボタンスイッチが押されているときは、else内の処理を行います。
このときはピン7がHIGHとなり、LEDが点灯します。


このスケッチでは、ボタンスイッチの状態に応じてLEDが点灯したり、消灯したりするはず!です。

動作確認

ボタンスイッチを押すとLEDが点灯し、離すと消灯しました!


www.youtube.com

まとめ

今回はボタンスイッチを使って、「押した」「押されていない」という操作の状況をArduinoに認識させることができました。

スイッチをHIGH、LOWというデジタル信号として扱い、プログラムを作る感覚を覚えていきたいです。




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門【Lチカ編】

プログラミング学習のためArduinoに触れてみようと思い立ちました。

プログラミングのHello World!みたいに、マイコンではLEDをチカチカ点滅させることから入門するようです。

この記事ではArduino Unoの内蔵LEDを光らせてみたいと思います。



目標

はじめから書き込まれているスケッチ(プログラム)により、内蔵LEDは初めから点滅しています。

自分で作成したスケッチを書き込むことでArduino UNOに内蔵されているLEDの点滅周期を変えることが目標です。

回路図

必要な部材はArduino UNOだけでブレッドボードやスイッチ等もいりません。

光らせる内蔵LEDは赤丸で囲んだ部分です。

f:id:ebisuke33:20210831214942p:plain
Lチカ

スケッチ

1.初期スケッチ
もともとArduinoに書き込まれていて、LEDが1秒周期で点滅するスケッチです。

void setup内でピンの初期設定を行いました。

内蔵LEDのLED_BUILTINをOUTPUT(出力)に設定しています。

void loop内のプログラムがArduinoの動作です。

digitalWrite関数でLED_BUILTIN(内蔵LED)をHIGH(点灯)やLOW(消灯)に切り替えています。

delay関数の()内の数字の単位はmsecで、指定された時間待つはたらきを持ちます。

したがって、このスケッチではLED_BUILTINをHIGH(点灯)にして1000 msec = 1秒待つ、LED_BUILTINをLOW(消灯)にして1秒待つ…を繰り返します。

void setup()  // LED_BUILTINをOUTPUTに設定
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // LEDを点灯させる
  delay(1000);                       // 1秒待つ
  digitalWrite(LED_BUILTIN, LOW);    // LEDを消灯させる
  delay(1000);                       // 1秒待つ
}


2.点滅周期を0.2秒に変更したスケッチ

delay関数の引数を200 = 0.2秒に変更しました。

これで点灯時間と消灯時間が0.2秒になり、はやい点滅になるはず!です。

void setup() {
  // LED_BUILTINをOUTPUTに設定
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // LEDを点灯させる
  delay(200);                       // 0.2秒待つ
  digitalWrite(LED_BUILTIN, LOW);    // LEDを消灯させる
  delay(200);                       // 0.2秒待つ
}

動作確認

1.初期スケッチ
スケッチ通り1秒周期でLEDが点滅しています。


www.youtube.com



2.点滅周期を0.2秒に変更したスケッチ
点滅が早くなりました!

さきほどより明らかにチカチカしています。


www.youtube.com


まとめ

目標とした内蔵LEDの点滅周期を変えることができました。

変更した箇所は少ないですが明らかに動作が変わっておもしろかったです。

まだまだ簡単なプログラムしかできませんが、少しずつ学んでいきたいと思います。





この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

AtCoder-ABC216 E - Amusement Park【Python解答例】

AtCoder Beginner Contest216のE問題についてPythonの解答例を記事にしていきます。
AtCoder Beginner Contest 216 - AtCoder


AtCoder Beginner Contest216 E - Amusement Park

E - Amusement Park

問題文

髙橋君は遊園地に遊びに行きました。
この遊園地には N 個のアトラクションがあり、i 個目のアトラクションの「楽しさ」の初期値は A i​ です。

髙橋君が i 個目のアトラクションに乗ると、以下の現象が順番に起きます。

髙橋君の「満足度」に、i 個目のアトラクションの現在の「楽しさ」が加算される。
i 個目のアトラクションの「楽しさ」が、1 減少する。
髙橋君の「満足度」の初期値は 0 です。髙橋君はアトラクションに合計 K 回まで乗ることができます。
最終的な髙橋君の「満足度」の最大値はいくつですか?

なお、髙橋君の「満足度」はアトラクションに乗ること以外で変化しません。

制約

・1≤N≤10 ^5
・1≤K≤2×10 ^9
・1≤A i​ ≤2×10 ^9
・入力は全て整数

解答例

N, K = map(int,input().split())

A = list(map(int, input().split()))

# 降順で最後の要素が0
A.sort(reverse=True)
A.append(0)

# 搭乗回数
k = 0
# 合計満足度
score = 0
# 搭乗回数が余るかどうか
flag = True

for i in range(N):
    # 次の要素と一致するまでに必要な搭乗回数
    tmp = (i + 1) * (A[i] - A[i+1])
    # tmpがKより大きければberak
    if k + tmp > K:
        break
    # スコアとkを更新
    score += (i + 1) * (A[i]*(A[i]+1) - (A[i+1])*(A[i+1]+1)) // 2
    k += tmp
else:
    flag = False

Kが0になるまでのスコア計算
if flag:
    div = (K-k) // (i+1)
    mod = (K-k) % (i+1)
    tmp = A[i]
    
    score += (i+1) * (tmp*(tmp+1) - (tmp-div)*(tmp-div+1))//2
    score += mod * (tmp-div)

print(score)

解説

乗るごとに満足度が1減るアトラクションがN個あり、K回搭乗できるときの満足度の最大値を答える問題です。

満足度のリストAは降順でソートしてから末尾に0を足します。

次のループで満足度の大きいアトラクションから搭乗回数kが制約のKを超えない範囲で乗り続けたときの満足度を貪欲に計算していきました。

i番目の要素からi+1番目の要素の満足度と一致するまで乗るとき、搭乗回数は(i + 1) * (A[i] - A[i+1])です。
満足度は1からA[i]までの和から、1からA[i+1]までの和を引いた値にi+1をかけた値です。

1からNまでの和についてはこちらを参照
ebisuke33.hatenablog.com

搭乗回数がKを超える場合は、ちょうどKになるまで満足度を足し合わせていきました。

最終的に求まったscoreを出力すればACでした。



ABC216の関連記事はこちら
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com