dockerとmysqlでデータ永続化

docker-composeでmysqlを起動する方法。

version: '3'
services:
    db:
        image: mysql:5.7
        ports:
            - "3306:3306"
        volumes:
            - ./db/data:/var/lib/mysql
        environment:
            MYSQL_DATABASE: test_database
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test

こんな感じで作るとホスト側の./db/dataディレクトリがコンテナの/var/lib/mysqlにマウントされる。(マウントという言葉の使い方あっているか?)
のでコンテナを削除してからまた起動してもデータが消えていない。
コンテナのmysqlに入る

docker container exec -it 2019_01_09_db_1 mysql -utest -ptest test_database;

テーブル作成

 CREATE TABLE user( id int PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci;

データ投入

INSERT INTO user (name) VALUES('name01'),('name02'),('name03');

コンテナ削除

docker rm -f 2019_01_09_db_1 

データ有る

mysql> select * from user;
+----+--------+
| id | name   |
+----+--------+
|  1 | name01 |
|  2 | name02 |
|  3 | name03 |
+----+--------+

マウントしないでやってみると

version: '3'
services:
    db:
        image: mysql:5.7
        ports:
            - "3306:3306"
        environment:
            MYSQL_DATABASE: test_database
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
mysql> show tables;
Empty set (0.00 sec)

となり、たしかにテーブルが消えていた。




おまけ

マウントした状態で、テーブル名などにタイポがあったので直して、コンテナを削除して再起動してもテーブル名が変わっていなくてつまづいた。
当然のことながら、マウントされている状態ではデータがホスト側に残っているので、その状態でコンテナを起動するとテーブルやその中のデータも保存されている。
一度ホスト側のマウントされているディレクトリを空にする必要が有る。

2018の振り返りと2019の目標

2018年やったこと

  • 大学院を退学した
  • 就職した

振り返ってみても特に語れるようなこともなかった。競技プログラミングに参加していた頃は問題について考察し、実装することで力がつくことが楽しかったし、頭が働いているという感覚もあって他のことについても結構考えられていた気がする。今は働いていると言っても一日中椅子に座ってぼーっとしていることが多く、靄がかかったようにうまく考えられなくなっている。虚しい時間は過ごすだけで消耗するので来年はもう少しうまくやりたい。

 

2019年の目標

キャリア

無理かもしれないけどできれば転職したい。会社の人はいい人が多いと思うけれど、自分の技術力が求められているレベルに達していない気がする。気が変わるかもしれないけど。

 

アウトプット

  • 週1でブログ
  • webアプリ2個(デプロイまで)
  • 勉強会に登壇

インプット

  • アウトプット目標のブログに書く用の技術書
  •  マネージメントスキル

その他(一つできれば良い)

 

大学院中退

退学 Advent Calendar 2018 - Adventar の22日目の記事です。

 前もって断っておくと、大学や大学院を中退しようとしている人がこの記事をよんでも得られるものはないと思います。当時の気持ちが残っているうちに中退するときにどんなことを考えていたのかを記録に残して置きたいと思って書きました。

 今年大学院を中退しました。学部は非情報系の理系学科で大学院は外部の情報系の大学院へ進学しました。この記事を書いている現在は都内のITベンチャー企業でソフトウェアエンジニアとして働いています。

 

大学院へ進学

学部3年の終わりか4年のころにプログラミングに興味を持ち始め、ソフトウェアエンジニアとして働きたいと思い始めました。ただこの頃は本当に全くプログラミングもできず、かつ明らかに他の人よりも出発が遅かったので、大学院で専門知識をつけてそれを武器にすればやっていけるのではないかと考えて大学院へ進学しました。今思えばこんな理由で進学したのが間違いでした。

 

研究を挫折

1年も立たずに心が折れました。研究テーマは学生が一人で考える必要がありました。自分には何が研究テーマとして成立して、何が成立しないのかもわからず、研究に着手することすらできませんでした。当然、専門知識を身につけるという目的を達成されることなく、研究生活は終了しました。この後1年以上だらだらと過ごすことになります。

 だらだら期

ひたすらNetflixやAmazonPrimeを見ていた気がします。このころに何をきっかけにかAtCoderにハマりだしました。一年くらいかけて水色まで到達できたのは嬉しかったな。

https://atcoder.jp/users/hkr

なにより、問題を解けるように勉強することで自分の能力が向上していることが自覚できたのがやりがいに繋がっていたのかなと思います。最近参加できていないのでまたいつか始めたいです。このあたりから、自分がどんなことにやる気が出てどんなことにやる気が出ないのかが少しわかってきました。

就活

学年としては修士3年になるころから就活を始めました。paiza経由で一番早く内定をもらったベンチャー企業に入社を決め、夏頃から働き始めて現在に至ります。

中退

内定をもらってすぐに中退しました。

 

気づきとか

今振り返ってみると、自分は自身の能力を大きく超えた難易度の課題に取り組むのがすごく苦手で、やる気が下がってしまいます。

能力と課題の難易度の間を埋める方法を自分で気づけたり、人からのサポートを受けられればむしろやる気が出るのですが、そうでない場合は途端にやる気が下がります。勇者のレベルが1なのにラスボスに挑まされているような気分になります。とりあえずレベル上げさせてくれ!となるのです。

一方でレベル上げは結構楽しくて好きです。ゲームでもレベル上げが意外と楽しかったりしますし、現実世界のレベル上げ(勉強とか)もあまり苦ではなかったりします。

働いていく上で自分のやる気を落とさないというのは大事なことだと思います。弊社では人が足りないので新卒の自分にもどこから手を付ければいいのかわからないタスクが降ってきたりします。そういったときに上に書いたことを思い出して、やる気を落とさないよう落とさないようやっていきたいです。

小さい方からk番目の値

億マス計算

C: 億マス計算 - AtCoder Regular Contest 037 | AtCoder

 

 すべてのマスを計算してからk番目の値を求めることはできない。

そもそも「小さい方からK番目の値がXである」とはどういうことか?

これは「X-1以下の数はK個未満しかないが、X以下の数はK個以上ある」ということ。別の言い方をすると「X以下の数がK個以上あるような最小のX」が小さい方からK番目の数。二分探索を使う。

「Xを決めたとき、X以下の数はK個以上あるか?」という問題を繰り返し解く。どうやって数えるか。

各行を一つずつ見ていく

 \displaystyle
   a_i  b_j  \leq X \Leftrightarrow b_j \leq X /  a_i(切り捨て)

i行目に含まれるK以下の数の個数は、 b_1,b_2,...,b_Nのうち X/a_i以下であるようなものの個数と一致

bをソートしておけば(再び)二分探索でO(log(N))時間で求まる。

おまけ 配列aの要素のうち、値がx以下であるものの数

int num =  upper_bound(a.begin(), a.end(), x)-a.begin();

ARC071_E TrBBnsformBBtion

問題

‘A'と'B'からなる文字列に対して

  1. ‘A’ -> ‘BB'、'B’ -> ‘AA'と変換
  2. ‘AAA'か'BBB'という部分文字列を削除

のいずれかの操作が可能である。 文字列S, TとQ個のクエリ(ai,bi,ci,di)が与えられる。各クエリは部分文字列S[ai]…S[bi]、T[ci]…T[di]に対応しており、両者を同じ文字列に変換できるかを判定せよ。

方針

全部の文字列をA(もしくはB)に置き換え、文字列の長さの差が3で割り切れれば同じ文字列にすることができ、そうでなければ出来ない。

ここでは、文字列を全てAにして比較する。 クエリごとに文字列の比較をしていくと間に合わないので、事前に累積和を計算しておく。 ここでいう累積和は、文字列をすべて'A'に変換するとき、i番目までの文字数である。 文字列S,Tそれぞれについて、Aなら1、Bなら2の足していく。

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;

int main() {
    string s, t;
    cin >> s >> t;
    vector<int> s_sum(100010), t_sum(100010);
    for(int i=0;i<s.size();i++) {
        int add;
        if(s[i] == 'A') add = 1;
        else add = 2;
        s_sum[i+1] = s_sum[i] + add;
    }
    for(int i=0;i<t.size();i++) {
        int add;
        if(t[i] == 'A') add = 1;
        else add = 2;
        t_sum[i+1] = t_sum[i] + add;
    }


    int q;
    cin >> q;
    vector<string> ans;
    for(int i=0;i<q;i++) {
        int a, b, c, d, num_s, num_t;
        cin >> a >> b >> c >> d;

        num_s = s_sum[b] - s_sum[a-1];
        num_t = t_sum[d] - t_sum[c-1];
        if(abs(num_s-num_t)%3 == 0)
            ans.push_back("YES");
        else
            ans.push_back("NO");
    }
    for(int i=0;i<q;i++) 
        cout << ans[i] << endl;
}

ARC071_D 井井井 / ###

問題

x軸に水平な直線がm本、y軸に水平な直線がn本引いてある。この中に存在している全ての長方形の面積を求める。

方針

x軸、y軸をそれぞれ別々に考える。x軸y軸それぞれについて、すべてのx[i] - x[j] (i >j)(y軸の場合(y[i]-y[j])の値を計算し、その結果をかけ合わせれば良い。 愚直にやるとまにあわない。のですべての直線の座標について、何回足して、何回引けばよいか考える。(x軸、y軸を別々に) 足す回数はx[i] - x[j] でいうところの、x[i]として計算する回数。 引く回数はx[[j]として計算する回数。 ここである座標kについて考える。 x[k]を足す回数(x[i]のところがx[k]になる回数)は k-1回、x[k]を引く回数はn-k回である。 これをy軸についても計算し、それをかければ良い。

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
ll mod = 1e9+7;
int main() {
    int n, m;
    cin >> n >> m;
    vector<ll> x(n), y(m);
    for(int i=0;i<n;i++) cin >> x[i];
    for(int i=0;i<m;i++) cin >> y[i];

    ll sum_x = 0, sum_y = 0;
    for(int i=0;i<n;i++) {
        sum_x += i * x[i] - (n-i-1) * x[i];
        sum_x %= mod;
    }
    for(int i=0;i<m;i++) {
        sum_y += i * y[i] - (m-i-1) * y[i];
        sum_y %= mod;
    }

    cout << sum_x * sum_y % mod << endl;
}

AGC012 B - Splatter Painting

 問題

N個の頂点とM個の辺のグラフが与えられる。最初、頂点は全て色0で塗られている。 それぞれの辺の長さは1である。 さらに、Q個の操作が与えられる。各操作は vi, di, ciという形式で与えられる。この意味は、頂点viから距離di以内にある頂点を色ciで上書きするということ。

方針

Q個の操作をそのままの順番で実行すると、計算量がO(N2)となり間に合わない。 Q個の操作を逆順に行う事を考える。逆順にすると、その操作によって塗られた頂点は二度と上書きされない。 dp[v][d]をつくり、同じ(v, d)について再び計算をしないようにすると(メモ化)、計算量はO(Q+(N+M)*max(di))となるらしい。

#include <iostream>
#include <vector>
#include <utility>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;

vector<int> g[100010];
vector<int> color(100010, 0);
vector< vector<bool> > dp;

void search(int d, int v, int c) {
    if(dp[v][d]) return;
    dp[v][d] = true;
    if(color[v]==0) color[v] = c;
    if(d==0) {
        //color[v] = c; 
        return;
    }
    search(d-1, v, c);
    for(int i=0;i<g[v].size();i++) {
        search(d-1, g[v][i], c);
    }

}

int main() {
    dp = vector< vector<bool> >(100010, vector<bool>(12, false));
    ll n, m;
    cin >> n >> m;
    for(int i=0;i<m;i++) {
        int ai, bi;
        cin >> ai >> bi;
        ai--; bi--;
        g[ai].push_back(bi);
        g[bi].push_back(ai);
    }
    int Q;
    cin >> Q;
    vector<int> v(Q), dv(Q), cv(Q);
    for(int i=0;i<Q;i++) {
        cin >> v[i] >> dv[i] >> cv[i];
        v[i]--;
    }

    for(int i=Q-1;i>=0;i--) {
        search(dv[i], v[i], cv[i]);
    }

    for(int i=0;i<n;i++) {
        cout << color[i] << endl;
    }

}