橙になりたいaquarium

にゃーんにゃーんにゃにゃーん

Hack Festa 2023 (トヨタCTF) に参加しました!WriteUp

普段とは違った話をします。研究室からHack Festa 2023というトヨタ主催のCTFに参加してきました。日米で開催され、国内1位総合2位となりました!

自己紹介

  • 大阪大学のB4です。

  • 研究では画像処理とか機械学習とかやってて、セキュリティとは無縁です。

  • 趣味では競技プログラミングをやってて、AtCoder黄色です。今年のICPC 2023 Asia Yokohama Regionalにも参加します。

  • バイトでは量子コンピューティングの関係のことをやっています。

目次

これまで

CTFとのこれまで

CTFはCpawCTFを埋めたり、高専や大学内で団体が開催しているCTFに参加したくらいです。Cryptoは比較的得意で、Miscやreversingはまだできる方ですが、webとかnetは一切わからないです。

今回のHack Festaは実機を触る以外ではこの中ではreversingしかなかったのでそれをやってました。というのも先輩たちがセキュリティを専門に研究していたりハード方面のことを趣味にしていたからです。私としては「数学とかアルゴリズムとか使う問題こないかなー」くらいの気持ちを持ちながらまぁ予想通りの問題セットがきた感じです。

今回はM1, M2の先輩と参加しました。M1のぽよさんの writeup はこちらです。

www.maaaaa.net

トヨタとのこれまで

トヨタ様には競プロで毎度お世話になってます。今年に入ってからだけで7回くらいAtCoder上で競技プログラミングのコンテストを開いていて、我々にとっては強力は後ろ盾だなぁと思っています。トヨタ自動車だけでこれで、トヨタシステムズとかも別にあったと思います。すごすぎ。

この記事を書いてる11/7の前々日、11/5(日)にもありました。そして11/11にもあります。11/5のコンテストでは37位の好成績でした。そのとき書いた解説↓

atcoder.jp

3月と8月にはトヨタ主催のオンサイトコンテストがあり、予選を通過して参加することができました。今年だけでトヨタグループのお金で3回東京に行けてて頭が上がりません…。

atcoder.jp

atcoder.jp

そのときに書いた記事はこちら。

shinchankosen.hatenadiary.jp

shinchankosen.hatenadiary.jp

WriteUp

pitstop puzzle (100点)

まずncのアレとtxtファイルが与えられました。txtは以下の通りです。

Car Engine Error Diagnostic Manual
===============================

1. Caesar Cipher (CXXX):
Encoding Key: C
1st Digit: Direction (1: Forward shift, 2: Backward shift)
2nd & 3rd Digits: Shift value
Example: C127 means a Caesar cipher shifting each letter 27 places backward in the alphabet.
Procedure: Shift each character in the encrypted string 27 places back to decode.

2. Base64 Encoding (BXXX):
Encoding Key: B
1st Digit: Input Reversed (1: Normal, 2: Reversed)
2nd Digit: Output Reversed (1: Normal, 2: Reversed)
Example: B22 implies a standard Base64 decoding, where the base64 payload is reversed, and also contains reversed text.

3. Hexadecimal Encoding (HXXX):
Encoding Key: H
1st Digit: Input Reversed (1: Normal, 2: Reversed)
2nd Digit: Output Reversed (1: Normal, 2: Reversed)
Example: H212 means decoding a hexadecimal encoded string and reversing the result.

4. Morse Code (MXXX):
Encoding Key: M
1st Digit: Direction (1: Normal, 2: Reversed)
Example: M221 implies decoding Morse Code and then reversing the result.

5. ASCII Conversion (AXXX):
Encoding Key: A
1st Digit: Direction (1: Normal, 2: Reversed)
Example: A214 implies converting ASCII to characters and then reversing the result.

6. XOR Operation (XYYY):
Encoding Key: X
1st digit is reserved for future use.
2nd & 3rd Digits: Key for XOR operation
Example: X112 implies XORing the string with the key "12". The output will be base64 encoded.

7. AES ECB Encryption (EXXX):
Encoding Key: E
1st digit is the padding character.
2nd and 3rd Digits: AES ECB Key (key, which will be padded with the 1st digit to make it 32 characters long)
Example: E242 implies decrypting the message using AES ECB with the key 42, padded to 32 characters with 2 and base64 encoded.

YXXXって形式の文字列と暗号が与えられて、10回くらい連続で復号してねーっていう問題です。

以下のCyberChefが復号に役立ちました。

gchq.github.io

  1. Caesar Cipher (CXXX): シーザー暗号です。† C++ † で実装しました。
  2. Base64 Encoding (BXXX): Base64の暗号です。CyberChefで解きました。
  3. Hexadecimal Encoding (HXXX): Hexの暗号です。CyberChef。
  4. Morse Code (MXXX): モールス信号です。ググってでてきた適当なサイトに入れました。
  5. ASCII Conversion (AXXX): CyberChef。
  6. XOR Operation (XYYY): CyberChef。
  7. AES ECB Encryption (EXXX): CyberChefを2段階でやる。

また、reverseが必要なときは適宜 † C++ † で実装した文字列反転プログラムに入れました。

10回くらい連続で正解するとフラグがでてきました。

smartcode (300点)

この問題もファイルとncのアレが与えられました。

まず、先輩がファイルをデコンパイルしてくれてCのコードをもらいました。

int calculate(char *param_1)

{
  int iVar1;
  char *local_20;
  char local_11;
  int local_10;
  int local_c;
  
  local_c = 1;
  local_10 = 0x5ba0;
  if (*param_1 == '\0') {
    local_10 = 0;
  }
  else {
    local_11 = *param_1;
    local_20 = param_1;
    do {
      iVar1 = (int)local_11;
      local_20 = local_20 + 1;
      local_11 = *local_20;
      local_10 = local_10 + (iVar1 + local_c * local_10) * 2;
      local_c = local_c + 1;
    } while (local_11 != '\0');
  }
  return local_10;
}
undefined8 main(void)

{
  size_t sVar1;
  char local_28 [28];
  int local_c;
  
  printf("INPUT CODE: ");
  fflush(stdout);
  fgets(local_28,0x15,stdin);
  sVar1 = strcspn(local_28,"\n");
  local_28[sVar1] = '\0';
  local_c = calculate(local_28);
  if (local_c == -0x14f5e200) {
    puts("ACCESS GRANTED");
    system("cat flag.txt");
    fflush(stdout);
  }
  else {
    puts("ACCESS DENIED");
    fflush(stdout);
  }
  return 0;
}

解読して以下のようにメモ書きとC++で動く形式にしました。

#include <bits/stdc++.h>
using namespace std;
#define all(v) (v).begin(),(v).end()
#define pb(a) push_back(a)
#define rep(i, n) for(int i=0;i<n;i++)
#define foa(e, v) for(auto& e : v)
using ll = long long;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL << 60);
#define dout(a) cout<<fixed<<setprecision(10)<<a<<endl;


int calculate(char *param_1)

{
  int iVar1;
  char *local_20;
  char local_11;
  int local_10;
  int local_c;
  
  local_c = 1;
  local_10 = 0x5ba0; //23456
  if (*param_1 == '\0') { 
    local_10 = 0;
  }
  else {
    local_11 = *param_1; // 1文字目
    local_20 = param_1; // param_1
    do {
      iVar1 = (int)local_11; // 順番に
      local_20 = local_20 + 1; // 2文字目以降
      local_11 = *local_20; // 1文字目
      local_10 += (iVar1 + local_c * local_10) * 2;  // めんどくさい
      local_c = local_c + 1; // インクリメント
    } while (local_11 != '\0');
  }
  return local_10;
}

int main(void)

{
    for(int i = 1; i <= 1000000000; i ++) {
        size_t sVar1;
        char local_28 [28];
        int local_c;
        string s = to_string(i);
        reverse(all(s));
        int id = 0;
        foa(e, s) {
            local_28[id ++] = e;
        }
        sVar1 = strcspn(local_28,"\n"); // 文字数
        local_28[sVar1] = '\0'; //null
        local_c = calculate(local_28);
        if (local_c == -0x14f5e200) { // -351658496 //  6144が割ったあまり ivar1の効果は3072
            cout << i << endl;
            puts("ACCESS GRANTED");
            // system("cat flag.txt");
            // fflush(stdout);
            break;
        }
    }
    
  return 0;
}

どうやら、20桁以上許容していて全探索は厳しそうです。また、オーバーフローが前提となっており、単純に数学で解くのが難しいです。

とりあえず立式してみました。mod 232合同式を用いました。二重階乗とかでてきて鬱でした。

modintとか使う意味もないしなーとなったり、拡張ユークリッドとかも使えないし…となっていたところ、合同式の右辺の定数部分を232の倍数を足して固定することを試みました。

すると、奇数のmodを順に考えることで、解が一意に定まっていきます。ただ、割り算がちゃんと行えるように † boost::multiprecision::cpp_int † で無限桁数を許容しました。

最終的に実装したものが以下です。


#include <bits/stdc++.h>
using namespace std;
#define all(v) (v).begin(),(v).end()
#define pb(a) push_back(a)
#define rep(i, n) for(int i=0;i<n;i++)
#define foa(e, v) for(auto& e : v)
#define dout(a) cout<<fixed<<setprecision(10)<<a<<endl;

#include <boost/multiprecision/cpp_int.hpp>
namespace mp = boost::multiprecision;
using ll = mp::cpp_int;
using i64 = long long;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL << 60);

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
        
    for(ll i = -351658496 + (1LL << 32); i < INF ; i += (1LL << 32)) {
        for(ll l =10; l <= 21; l ++) {
            ll sum = 0;
            for(int j = 1; j <= l; j ++) {
                sum *= (ll)(j * 2 + 1);
                sum += 96;
            }
            {
                ll sum1 = 23456;
                for(int j = 1; j <= l; j ++) {
                    sum1 *= (ll)(j * 2 + 1);
                }
                sum += sum1;
            }
            assert(sum >= 0);
            ll val = i - sum;
            if(val < 0) continue;
            val /= 2;
            string s = "";
            bool ng = false;
            for(ll j = l; j >= 5; j --) {
                bool f = false;
                for(int k = 0; k < 10; k ++) {
                    if((val - k) % (j * 2 + 1) == 0) {
                        val -= k;
                        val /= (j * 2 + 1);
                        s += char('0' + k);
                        f = true;
                        break;
                    }
                }
                if(!f) {
                    ng = true;
                    break;
                }
            }
            if(ng) continue;
            bool ok = false;
            rep(k1, 10) rep(k2, 10) rep(k3, 10) rep(k4, 10) {
                if(ok) break;
                if(ll(k1 * 315 + k2 * 63 + k3 * 9 + k4) == val) {
                    s += char('0' + k4);
                    s += char('0' + k3);
                    s += char('0' + k2);
                    s += char('0' + k1);
                    ok = true;
                    break;
                }
            }
            if(!ok) continue;
            reverse(all(s));
            cout << (i64)i << " " << l << " " << (i64)sum << endl;
            cout << s << endl;
            
            return 0;
        }
    }
    
    return 0;
}

10通りから対象の奇数で割り切れるかーを試すのに、奇数が大きいときは1通りで割り切れたら貪欲にそれを採用してよいです。しかし、残りの4桁は全探索しました。

実行すると、10秒で 00865208553 とでました。フラグ入手。ありがとう。

Toyota Programming Contest 2023 Summer Final 参加記

自己紹介

AtCoder黄色のshinchan(@Sophia_maki)です。 院試受かったわーいわーい。

ヒューリスティックは緑コーダーで、ヒュのアルゴリズム(ビームサーチ、焼きなまし、山登り法)はなにも知りません。 一応サンダー本は一周して、概要は理解してました。実装はしたことないです。

先日インターン2社受けて両方落ちました、そんなぁ。

目次

予選

ヒープの気持ちになって思いついたのを全部やったらちゃんと上がっていきました。

  • textで0を出力すると4.23Mになります。
  • 条件を満たさない箇所をランダムで選んで入れ替えるを繰り返し、2秒間やり続けるようにしたつもりが、なぜか975000点に…
  • >と<を逆にしてました。それはそう。直すと12.3M
    • 大きい数字から順に、下まで持って行くのを繰り返しました。13.3M

このへんでボーダー

  • 小さい数字から順に、上まで持って行くのを追加しました。13.42M
  • その2つをランダムでやるようにしました。13.44M
  • 時間計測の経験がなかったので気付かなかったのですが、秒が整数になってることに気づきました。人が使ってるのパクりました。13441420
  • パラメータ調整13442230

最強コンは落ちた

東京行き

前日まで

前々日、springと同じ動きなのですが、前回と同じ競プロerと池袋で遊びました。楽しかったです。初のシーシャに誘われました。タバコ普段吸わないので酸欠になりました。

その後、かねてより一緒に飲みたい!っとお互い言っていた しいさん に泊まらせていただきました。初対面だったのですが一応大学とバイトの先輩です。トヨタコン前日は歌舞伎町でステーキ食べたり飲んだりしました。なんか毎回同じ場所に行ってる気がしますね。早めに渋谷のホテルについて洗濯したりABCに出たりしました。それと、あまり寝れませんでした…。

当日

本番まで

名札ですが、アイコンを入れるのがけっこういいなーと思った結果こうなりました。

会場(ビル)に着いたのも会場(部屋)についたのもコンテスタントでは一番乗りでした、やったぜ。

↓ これはなに

場所的に近かったので主に運営側にいた つもいよろず さんに雑談ふっかける時間が多かったと思います。

本番

インタラクティブでちょっと驚きました。入れるのと出すのを別々で最適化することにします。とりあえず正の点数を出すことを試みます。UnionFindを利用して、その場所においていいかの判定をしたり、葉ならば優先的に置いたりしました。実装バグらせたりそもそも考察漏れがあったりして、238106573513 点に開始88分かかりました、たいへんたいへん。

後半の出すパートの方が改善しやすいと思っていろいろ考えたのですが、ここで書いたことのない焼きなましを書いてみました、改善しませんでした、そんなぁ。

前半の最適化を試みます。BFSで距離と残っている数字に応じて置く場所を決めました。終了5分前の提出で252806416456点となり、175位でした。なお、これが通らなかったら正の点数内で最下位でした。

表彰式・懇親会

springとはがらっと入賞が変わるもんだなーという印象です。入賞内にも知り合いが3人くらいいました。塚本は同学年で5年の付き合いになるのもあって、3位はただただすごい、おめでとう。

懇親会では、去年インターンでお世話になった方が何人かいて、近況報告するなどしました。

のいみさん11位かわいそうだった、私は175位なので低みの見物です。

二次会

にckなめさんやjabeeさんに二次会どうしたこうしたと声をかけていました。また、同じ大学の先輩(初対面)のぷっちょさんもいたのですが、6人くらいほしいなーと思っていて、mtsdさんのグループをマージして7人になりました。魚がとてもおいしかったです。

当初は翌日帰る予定だったのですが、にckなめさんに「1回なら新幹線の日変更できるよ!」と教えてもらい、宿をとってないのもあって、当日帰ることにしました。

二次会を途中で抜けて、ほぼ終電で帰宅しました(終電じゃなかったのは阪急が強かった)。

今後

院試も終わってようやく平穏な生活が訪れそうです。

10月下旬にはトヨタが主催するCTFもあり、研究室の関係で参加することになりました。というわけで2ヶ月後も東京に行けます。トヨタ様本当にありがとう…。

作問と解説集

shinchan (@Sophia_maki) が作った問題とAtCoder上の問題に対する解説のリンク

作問

OUPC2023

ABHIJLQの原案。原案のまま出されたのはABL。

解説のみ

ICPC2023国内予選参加記

AtCoder黄色のshinchan(@Sophia_maki)です。ICPC国内予選通過しました!!!!!!!!

目次

チームの紹介

チーム名はkotamanegi_mijingiriです。メンバーは以下の3人です。

  • KowerKoint (@KowerKoint2010)

一番レート高い。実装とか早解きの鬼。ABCで取った100位以内の順位のビンゴとかやっててめっちゃ埋まっててすごい。

  • Daylight (@Daylight_pro)

DPとかデータ構造が得意らしいです。DPが出たら投げようと思いました。

パズルが得意です。数学とかFPSとかもちょっとだけできます。DPと早解きと実装が苦手です。

黄色下位3人チームで、阪大では2軍でした。ただ始めてからずっと勢いがすごいkureha氏に負ける可能性はじゅうぶんあると考えてました。実際私たちは学内3位になりました。

前日まで

チーム名の決定

チーム練

6月11日、AHCがあった日に吹田キャンパスに集まりました。daylightさんとは初対面でした。

twitterを見ると、ちょうど同じ時間帯にAHCをサボってチーム練をしているチームがあるではありませんか。

れたすさん、りきぽんさん、はちじさんのチーム(tenkei998244353)でした。彼らが2018国内予選をやるということで、私たちも対抗して同じのを解くことにしました。

結果として、5完早解きという形になりました。このとき、KowerKointくんに常にpcに張り付いてもらうのが最適だと考え、私は実装しないことに決めました。

あとlettuce_mijingiriも行うことにしました(?)

個人練(儀式)

模擬国内

KowerKointくんが参加できないということで、Daylightくんと2人ででることに。家がわりと近かったので私の家にしました。

A, BをDaylightくんがやって、僕はCを見る方針となりました。

Cでわりと苦戦してしまいました。KowerKointくんいないしーと思って自分で実装したのが間違いでした。DはDaylightのD、DPのDです。良い高速化を見つけて解いてくれました、つよい。

Eはなんかいい感じになりました。僕も実装しましたが、拡張ユークリッド書く以外は実装量かなり少ない問題で助かりました。

2人でこの結果、いい感じ。

本番

方針

早解きが得意なKowerKointくんにA, Bを解いてもらい、CをDaylightくん、Dを私がやることになりました。 また、私は一切実装をしません。他2人の好みで、キーボードがUS配列で、Neovim拡張を入れた環境でした。私は元々実装苦手なのもあって、すべて他2人にmarunageする方針を取りました。

また、パズルっぽいのがでたら私に回してもらい、逆にDPっぽいのはmarunageする方針でした。

本番中

A問題ACまで

始まった途端コンテストページにアクセスできなくなりました。httpsにしてたらダメだったみたい(リハーサルでは大丈夫だったのに)。きたむーが審議申し立てを提案してくれたのでやってみた、通らなかった。

さて、問題見れない、印刷できないことには、KowerKointはフォルダやファイル作ってマクロやライブラリを書くとして、他2人はやることがないです。

7, 8分ほどして問題が見れて印刷できたので各々取り掛かりました。KowerKointくんがAを通してくれました。

B問題ACまで

Cがパズル、DがDPっぽいと思ってDaylightくんと問題を交換しました。

とはいっても、まずはCを2人で考えようとなりました。行の偶奇と列の偶奇に着目してみてはという助言に従い、市松模様を考えました。これで白い部分を左に、黒い部分を右に寄せたらなんかいけそうと思いました。

KowerKointくんがBをACしました。

C問題ACまで

合ってるかどうかの確認ができるタイプの問題なので、解法をKowerKointくんに伝えて実装してもらいました。他2人はD以降見てました。 どうやらCはNが偶数のときにうまくいってないみたいです。Daylightくんが、右に寄せた部分の上半分と下半分を逆にしてみてはと言ってくれて、KowerKointくんが実装してACしました。

D問題ACまで

このタイプの問題は2冪を考えるとよく、1, 2, 4, 8, 16, 32, 64で、高々7つですべて構築できることがわかります。 なので6個以下でできないことを確かめるといいです。単調増加で、総和がNで、bitsetが使えるのでーって感じで全探索で間に合う気がしてきました。って考えてる間にKowerKointくんがEの考察を終わらせたみたいで、先に実装してました。違ったようです。Dの実装をDaylightくんが始めました。6重forで書くのはかなり厳しく、KowerKointくんのEと交互に実装してました。途中でdfsでの実装に切り替え、完全にペアプログラミング状態でした。その際、bitsetまわりを1, 2行だけ私が実装してしまいました。まぁ、ACしたのでよしです。

その後

順位表を見るとEを解けば確実だと感じました。F, GのACもちょっとだけいるけど望み薄いなぁとなりました。Fは見た瞬間にチームメイトと爆笑してました。Gはどうやって重複除くんだろうとなってました。

というわけで、3人で確実にEを通し切ろうという方針に。なにもできません、おわり。

結果

21位!!!!!通過しました!!!!!

さいごに

コーチのolpheさん、めっちゃmarunageしてました、すみませんでしたありがとうございます。

阪大初の3チーム通過!!














院試今月末!やばい!

WaniCTF2023 Writeup

結果・感想

WaniCTF2023に参加しました。高専時代の先輩たちのチームに混ぜてもらいました。

20位でした!個人では、cryptoのpqqp, fusion、miscのrange_xor, int_generatorを解きました。 4つとも数学とか競プロっぽくて面白かったです。

もくじ

解説

自分が解いた問題の解説をします。

Misc range-xor

この問題は完全に競プロです。i番目の整数まで見て、その時点で0~1023の各整数が作れるか、作れるなら何通りかを保管するDP。modintとboolを持てばよい。boolをわざわざ持つ理由としては、modをしたときにもしかしたら0になってしまう可能性があるため(さすがにないとは思った)。

#include <bits/stdc++.h>
#define be(v) (v).begin(),(v).end()
#define pb(q) push_back(q)
#define rep(i, n) for(int i=0;i<n;i++)
#define all(i, v) for(auto& i : v)
typedef long long ll;
using namespace std;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL<<60);
#define doublecout(a) cout<<fixed<<setprecision(10)<<a<<endl;

template<int MOD> struct Modint {
    long long val;
    constexpr Modint(long long v = 0) noexcept : val(v % MOD) { if (val < 0) val += MOD; }
    constexpr int mod() const { return MOD; }
    constexpr Modint operator - () const noexcept { return val ? MOD - val : 0; }
    constexpr Modint operator + (const Modint& r) const noexcept { return Modint(*this) += r; }
    constexpr Modint operator - (const Modint& r) const noexcept { return Modint(*this) -= r; }
    constexpr Modint operator * (const Modint& r) const noexcept { return Modint(*this) *= r; }
    constexpr Modint operator / (const Modint& r) const noexcept { return Modint(*this) /= r; }
    constexpr Modint& operator += (const Modint& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Modint& operator -= (const Modint& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Modint& operator *= (const Modint& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Modint& operator /= (const Modint& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b, swap(a, b);
            u -= t * v, swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Modint& r) const noexcept { return this->val == r.val; }
    constexpr bool operator != (const Modint& r) const noexcept { return this->val != r.val; }
    friend constexpr istream& operator >> (istream& is, Modint<MOD>& x) noexcept {
        is >> x.val;
        x.val %= MOD;
        if (x.val < 0) x.val += MOD;
        return is;
    }
    friend constexpr ostream& operator << (ostream& os, const Modint<MOD>& x) noexcept {
        return os << x.val;
    }
    constexpr Modint<MOD> pow(long long n) noexcept {
        if (n == 0) return 1;
        if (n < 0) return this->pow(-n).inv();
        Modint<MOD> ret = pow(n >> 1);
        ret *= ret;
        if (n & 1) ret *= *this;
        return ret;
    }
    constexpr Modint<MOD> inv() noexcept {
        long long a = this->val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b, swap(a, b);
            u -= t * v, swap(u, v);
        }
        return Modint<MOD>(u);
    }
};

const int MOD = MOD7;
using mint = Modint<MOD>;

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n = 1000;
    vector<mint> dp1(1024, 0);
    vector<int> dp2(1024, 0);
    dp1[0] = 1;
    dp2[0] = 1;

    rep(i, n) {
        int a;
        cin >> a;
        vector<mint> nx1(1024, 0);
        vector<int> nx2(1024, 0);
        int num = min(a, 1000 - a);
        for(int j = 0; j < 1024; j ++) {
            nx1[j ^ a] += dp1[j];
            nx2[j ^ a] |= dp2[j];
            if(num != a) {
                swap(num, a);
                nx1[j ^ a] += dp1[j];
                nx2[j ^ a] |= dp2[j];
            }
        }
        swap(nx1, dp1);
        swap(nx2, dp2);
    }
    for(int i = 0; i < 1024; i ++) {
        if(dp2[i]) {
            cout << dp1[i].val << endl;
            return 0;
        }
    }

    return 0;
}

コンパイル、実行し、入力で与えられた整数を入れると461905191が出力される。

Misc int-generator

解いたときFAの次だったので興奮した。

chall.pyを以下のように改造して実行した。 つまり、flag1, 2は前から探索、flag3は後ろから探索すると見つかりやすい。 flag2は数分待たないとでてこなかった。申し訳程度に書き換えて実行したらでた。

def f(x):
    if x == 0 or x == 2**36:
        return -x
    if x * x % (2**36) != 0:
        return -x
    else:
        return -x * (x - (2**36)) // (2**36)


def g(x):
    ret = x * 2 + x // 3 * 10 - x // 5 * 10 + x // 7 * 10
    ret = ret - ret % 2 + 1
    return ret, x // 100 % 100


def digit(x):
    cnt = 0
    while x > 0:
        cnt += 1
        x //= 10
    return cnt


def pad(x, cnt):
    minus = False
    if x < 0:
        minus = True
        x, cnt = g(-x)
    sub = 16 - digit(x)
    ret = x
    for i in range(sub - digit(cnt)):
        ret *= 10
        if minus:
            ret += pow(x % 10, x % 10 * i, 10)
        else:
            ret += pow(i % 10 - i % 2, i % 10 - i % 2 + 1, 10)
    ret += cnt * 10 ** (16 - digit(cnt))
    return ret


def int_generator(x):
    ret = -x
    x_ = f(x)
    cnt = 1
    while x_ > 0:
        ret = x_
        x_ = f(x_)
        cnt += 1
    return pad(ret, cnt)


X = 1008844668800884
for i in range(100000000):
    if int_generator(i) == X:
        print(i)
        break

X = 2264663430088446
for i in range(100000000):
    if int_generator(i) == X:
        print(i)
        break

X = 6772814078400884
for i in range(1 << 35, 0, -1):
    if int_generator(i) == X:
        print(i)
        break

実行結果

0
26476544
34359738368

Crypto pqqp

p, qを求めるヒントとして(pow(p, q, n) + pow(q, p, n)) % nの値が与えられている。 実は、フェルマーの小定理から、これはp+qの値に等しいことがわかる。s = p + qとn = pqの値がわかっているため、p, qの値が求められる。

import math
from Crypto.Util.number import long_to_bytes
n = 31091873146151684702346697466440613735531637654275447575291598179592628060572504006592135492973043411815280891993199034777719870850799089897168085047048378272819058803065113379019008507510986769455940142811531136852870338791250795366205893855348781371512284111378891370478371411301254489215000780458922500687478483283322613251724695102723186321742517119591901360757969517310504966575430365399690954997486594218980759733095291730584373437650522970915694757258900454543353223174171853107240771137143529755378972874283257666907453865488035224546093536708315002894545985583989999371144395769770808331516837626499129978673
e = 65537
c = 8684906481438508573968896111659984335865272165432265041057101157430256966786557751789191602935468100847192376663008622284826181320172683198164506759845864516469802014329598451852239038384416618987741292207766327548154266633297700915040296215377667970132408099403332011754465837054374292852328207923589678536677872566937644721634580238023851454550310188983635594839900790613037364784226067124711011860626624755116537552485825032787844602819348195953433376940798931002512240466327027245293290482539610349984475078766298749218537656506613924572126356742596543967759702604297374075452829941316449560673537151923549844071
s = 352657755607663100038622776859029499529417617019439696287530095700910959137402713559381875825340037254723667371717152486958935653311880986170756144651263966436545612682410692937049160751729509952242950101025748701560375826993882594934424780117827552101647884709187711590428804826054603956840883672204048820926

a = math.isqrt(s * s - n * 4)
p = (s + a) // 2
q = (s - a) // 2

d = pow(e, -1, (p - 1) * (q - 1))

print(long_to_bytes(pow(c, d, p * q)))

実行結果

b'FLAG{p_q_p_q_521d0bd0c28300f}'

Crypto fusion

与えられたshall.pyを見つめると、まずやることとして、rの奇数bit目と偶数bit目をpとqに分解することができる。

from Crypto.PublicKey import RSA

RSAkeys = RSA.generate(2048)
p = RSAkeys.p
q = RSAkeys.q
n = RSAkeys.n
e = RSAkeys.e
m = b"FAKE{<REDACTED>}"
c = pow(int.from_bytes(m, "big"), e, n)

mask = int("55" * 128, 16)
r = p & mask
mask = mask << 1
r += q & mask

print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
print(f"r = {r}")

最下位bitはnが1、p, qの片方が1なのでもう片方も1となる。

そして、n[i] = (繰り上がり) + p[i] * q[0] + p[i - 1] * q[1] + ... + p[0]q[i]となり、この中で確定していないのはp[i]とq[i]の片方だけである。p[0]=q[0]=1なので、p[i], q[i]の値によって1足されるかどうかとなる。そしてこれは偶奇を見ればよく、「繰り上がりを含めた総和」と「nのi bit目」の差が奇数なら1にする、偶数なら0にすればよい。そうすることで最終的な差が偶数となり、2で割って繰り上がりにできる。

mask(len(bin(mask)) - 2) = 1023なので1023bitは確定しているっぽい。ので、そこまではp, qを確定させられるが…。

それ以降はbit全探索を使います!p, qどっちでもいいのですが、続きの15bitくらいをbit全探索しました。nで割り切れるものがあればp, qを求めることができたと言えます。

まず以下でp, qを求めます。

mask = int("55" * 128, 16)
n = 27827431791848080510562137781647062324705519074578573542080709104213290885384138112622589204213039784586739531100900121818773231746353628701496871262808779177634066307811340728596967443136248066021733132197733950698309054408992256119278475934840426097782450035074949407003770020982281271016621089217842433829236239812065860591373247969334485969558679735740571326071758317172261557282013095697983483074361658192130930535327572516432407351968014347094777815311598324897654188279810868213771660240365442631965923595072542164009330360016248531635617943805455233362064406931834698027641363345541747316319322362708173430359
e = 65537
c = 887926220667968890879323993322751057453505329282464121192166661668652988472392200833617263356802400786530829198630338132461040854817240045862231163192066406864853778440878582265466417227185832620254137042793856626244988925048088111119004607890025763414508753895225492623193311559922084796417413460281461365304057774060057555727153509262542834065135887011058656162069317322056106544821682305831737729496650051318517028889255487115139500943568231274002663378391765162497239270806776752479703679390618212766047550742574483461059727193901578391568568448774297557525118817107928003001667639915132073895805521242644001132
r = 163104269992791295067767008325597264071947458742400688173529362951284000168497975807685789656545622164680196654779928766806798485048740155505566331845589263626813345997348999250857394231703013905659296268991584448212774337704919390397516784976219511463415022562211148136000912563325229529692182027300627232945

num = r
d = 1
p = 0
q = 0
for i in range(1023):
    if i & 1:
        if num & 1:
            q += d
    else :
        if num & 1:
            p += d
    num >>= 1
    d <<= 1


q += 1
d = 1
k = 0


for i in range(1, 1023):
    d <<= 1
    ans = k - (n >> i & 1)
    
    for j in range(i + 1):
        ans += (p >> j & 1) * (q >> (i - j) & 1)
        
    if ((ans % 2) + 2) % 2 == 1:
        ans += 1
        if i & 1:
            p += d
        else :
            q += d
    k = ans // 2

lim = 1 << 15

ans1 = []
ans2 = []
flag = False
for bit in range(lim):
    pnow = p
    for i in range(15):
        if bit >> i & 1:
            pnow += 1 << (1023 + i)
    if n % pnow == 0:
        ans1.append(pnow)
        ans2.append(n // pnow)
        
for bit in range(lim):
    pnow = q # qnowに変える意味ない
    for i in range(15):
        if bit >> i & 1:
            pnow += 1 << (1023 + i)
    if n % pnow == 0:
        ans1.append(n // pnow)
        ans2.append(pnow)
        

print(ans1[0])
print(ans2[0])

出力はこうなりました。上をp、下をqとしましょう。

158982482761532936352511330658816601706429032258548834912125273034488997046490434244533210801707343036413253864390713073589522875165458597351216083121996049787719375116167821890856038886439850595034188390482176192712663134014807479657958971828756944383908361170612935098217276884087156156071510999037803600539
175034578077309701984181964268308339398388268617712324238289276804454728925416562859929986131078776699682249344599789995987665924833218204252743836262945362936105111796551388997258331666189228142473360653861656406464150833269243661900931849107877401563507303666653995787300006491378116771557849415731270875381

これらを使ってフラグを求めます。

from Crypto.Util.number import *

p = 158982482761532936352511330658816601706429032258548834912125273034488997046490434244533210801707343036413253864390713073589522875165458597351216083121996049787719375116167821890856038886439850595034188390482176192712663134014807479657958971828756944383908361170612935098217276884087156156071510999037803600539
q = 175034578077309701984181964268308339398388268617712324238289276804454728925416562859929986131078776699682249344599789995987665924833218204252743836262945362936105111796551388997258331666189228142473360653861656406464150833269243661900931849107877401563507303666653995787300006491378116771557849415731270875381

e = 65537

d = pow(e, -1, (p - 1) * (q - 1))

c = 887926220667968890879323993322751057453505329282464121192166661668652988472392200833617263356802400786530829198630338132461040854817240045862231163192066406864853778440878582265466417227185832620254137042793856626244988925048088111119004607890025763414508753895225492623193311559922084796417413460281461365304057774060057555727153509262542834065135887011058656162069317322056106544821682305831737729496650051318517028889255487115139500943568231274002663378391765162497239270806776752479703679390618212766047550742574483461059727193901578391568568448774297557525118817107928003001667639915132073895805521242644001132

m = pow(c, d, p * q)
m = long_to_bytes(m)
print(m.decode())

実行結果は以下。

FLAG{sequ4ntia1_prim4_fact0rizati0n}

Crypto fusion あとがき

さて、今気づいたのですが、print(len(bin(mask)) - 2)で1023だったので1023bit確定させられる!って言ってたんですが、maskを1bitずらしていることに注目すれば、1024bit確定させられることに気づき、そこまで確定したらpq = nになりました。bit全探索いらなかった…。

mask = int("55" * 128, 16)
n = 27827431791848080510562137781647062324705519074578573542080709104213290885384138112622589204213039784586739531100900121818773231746353628701496871262808779177634066307811340728596967443136248066021733132197733950698309054408992256119278475934840426097782450035074949407003770020982281271016621089217842433829236239812065860591373247969334485969558679735740571326071758317172261557282013095697983483074361658192130930535327572516432407351968014347094777815311598324897654188279810868213771660240365442631965923595072542164009330360016248531635617943805455233362064406931834698027641363345541747316319322362708173430359
e = 65537
c = 887926220667968890879323993322751057453505329282464121192166661668652988472392200833617263356802400786530829198630338132461040854817240045862231163192066406864853778440878582265466417227185832620254137042793856626244988925048088111119004607890025763414508753895225492623193311559922084796417413460281461365304057774060057555727153509262542834065135887011058656162069317322056106544821682305831737729496650051318517028889255487115139500943568231274002663378391765162497239270806776752479703679390618212766047550742574483461059727193901578391568568448774297557525118817107928003001667639915132073895805521242644001132
r = 163104269992791295067767008325597264071947458742400688173529362951284000168497975807685789656545622164680196654779928766806798485048740155505566331845589263626813345997348999250857394231703013905659296268991584448212774337704919390397516784976219511463415022562211148136000912563325229529692182027300627232945

num = r
d = 1
p = 0
q = 0
for i in range(1024):
    if i & 1:
        if num & 1:
            q += d
    else :
        if num & 1:
            p += d
    num >>= 1
    d <<= 1

q += 1
d = 1
k = 0

for i in range(1, 1024):
    d <<= 1
    ans = k - (n >> i & 1)
    
    for j in range(i + 1):
        ans += (p >> j & 1) * (q >> (i - j) & 1)
        
    if ((ans % 2) + 2) % 2 == 1:
        ans += 1
        if i & 1:
            p += d
        else :
            q += d
    k = ans // 2

print(p)
print(q)
print(p * q == n)

実行結果

158982482761532936352511330658816601706429032258548834912125273034488997046490434244533210801707343036413253864390713073589522875165458597351216083121996049787719375116167821890856038886439850595034188390482176192712663134014807479657958971828756944383908361170612935098217276884087156156071510999037803600539
175034578077309701984181964268308339398388268617712324238289276804454728925416562859929986131078776699682249344599789995987665924833218204252743836262945362936105111796551388997258331666189228142473360653861656406464150833269243661900931849107877401563507303666653995787300006491378116771557849415731270875381
True

余談

CTFは実質未経験で、普段は競プロerをやっています。 AtCoder黄色で、その知識で殴った感じです。

これまでのCTFの経験と言えば、高専時代に学内のCTF会に参加したのと、CpawCTFを埋めたくらいしかないです。阪大だと2年くらいでCTFの授業があるらしいですが編入生なので知らない子です…。

さて、このGWはといえば、4/30は阪大のいちょう祭に行き、その後は実家でサークル活動という名の競プロをやっておりました。WaniCTFのあった3日間に重なって3日間のHUPCがありました。また、競技プログラミング部RAINBOUでは部内ライブラリを作成をしております。日々、「ここはこうしたい、えーグラフテンプレートなんて使わないよ~」という宗教戦争が勃発中でございます。

Toyota Programming Contest 2023 Spring Final 参加記

自己紹介

先日AtCoder黄色になりました、shinchan(@Sophia_maki)です。最近そふぃあとも名乗り始めました。

目次

予選

Qual A

「ふぁ!?3/18???TOEIC前日やんけ!前日なら大丈夫やな!うん!」 といいながらレジりました。3完でした(カス)。

Qual B

5完でした。イベント通過は確信しました。 決勝逆ボーダーだとわかり発狂しました。

後日、繰り上がりメールが来ました。2/27にメールが来たのですが、2/28にメールが来た人に会場で会ったのでボーダーではないらしいです。

東京行き

準備とか

品川にホテルをとりました。帰る日はそのままTOEICなので帰りやすさ重視です。 初めは渋谷に取ろうとしてたのですが、メールが来た時点で残ってるのはカプセルホテルとラブホくらいでした。毎度お世話になってますbooking.comさん。

前々日

朝出発し、池袋まで行きました。 インターンで知り合った競プロerと池袋で遊びました。楽しかったです。 さて、実は宿を取ってなかったのでカラオケのフリータイムで泊まりました。とは言っても寝れなかったのでTOEICの勉強したり歌ったりしてました。 5:00で終わりなので早朝の池袋を歩いて快活に移動してシャワー浴びて寝ました。合計で1泊2000円いってないのはアド。

前日

8:00に起床して新宿に移動しました。高専出身の人とエンカして新宿御苑で歩き疲れました。ラーメンおいしかった。その後下北沢に行きました。もちろんぼっちざろっくの聖地巡礼です。わりと早く終わってしまったので下北沢といえば?ということであの場所へ…(きたない)。

その後はお土産を買うのに付き合ってもらい、わかれて品川のホテルに行きました。

さすがに眠たくていったん寝たのですが、起きたらちょうどいい時間だったので晩御飯誰かと食べたいなとなってツイートしたところ、Hokutoさんが来てくれました!

初対面だったのですが3時間くらいだべりました。

当日

本番まで

出発5分前に、みんな名札を作っていることに気づきました。 そこで、twitterプロフィールをスクショして印刷することにしました(???)。

それまで登場してなかった推し↓

知り合いや周りの人達とおしゃべりしました。 大学の先輩のkotamanegiさんと話していたところ、となりの人が戻ってきました。 まさかのmaspyさんでびっくりしました(実在したんだ…)。 yukicoderで作問したときにtesterをしていただいたのでお礼を言いました。

私の右の人はりあんさんでした↓

chokudaiさんと握手したりしました。

本番

まずBを見ました。わかりませんでした。

Cを見ました。わかりませんでした。

Aを見ました。すぐ解けました。

Bを見ました。わかりませんでした。

Cを見ました。わかりませんでした。

Dを見ました。8ペナの末に解けました(些細なミスでした)。

Bを見ました。わかりませんでした。

Cを見ました。わかりませんでした。

終わりました。疲れて「これ立ったら倒れるやつだ」と思いながらゆっくり立ちました。

まぁD通せたのは良かったのかなと思います。

イベント

rngさんのやつとか面白かったです。こういう内輪ノリ好き。 雑談コーナーでひたすらしゃべってました。初めは主にまよこーんさんとしゃべってた覚えがあります。その後はいろんな人としゃべりました。懇親会まで含めて、参加者やatcoder関係の人とか含めて60人くらいしゃべったと思います。頭が働いてないので理性を飛ばして人にしゃべりかけてました。ただのダル絡みでは。

大宴会

大宴会も同じような感じです。あまり酒を飲んだ覚えはないですが、魚おいしかったです。サンダーさんと握手しました。ここでも会いたかった人いっぱいいました。30人はしゃべったと思います。

帰って品川のホテルに泊まりました。

翌日

案外時間がやばいことに気づきました。直で行きました。会場は大阪大学豊中キャンパスでした(私は工学部なので吹田キャンパスにいます)。

疲れすぎてなんも考えられませんでした。3日間楽しすぎてぼーっとしちゃいました。

お金という面では受験料7000円は損ですが交通費と宿泊費出てるのでだいぶ得ですね(覚悟の上でした)。

TOEICの連れととんかつを食べたあとABCにでました。飽きて撤退したのですが、これまで飽きるなんてことはなかったのでちょっと不思議に思ってました。

翌日、いろいろあって…

今後

しばらく競プロ休止します。理由としては今まで定期的にでてない期間もあったりしたので、またいったん休む期間を作った方がいいと思ったからです。 あと単純に院試とかのためです。それと、いつも言ってるけどしばらく休みたい…。

今年はインターン行こうか迷う。興味でるとこあるかな。

AtCoder黄色になりました!!

shinchan(@Sophia_maki)です。 この記事はAtCoder入黄記事ですがCodeforces入橙記事を兼ねています。

目次

自己紹介

現在大学3年生で競プロを嗜んでいる工学部生です。

本題

Codeforces

Codeforces Round #802 (Div. 2)で、CodeforcesのMasterになりました。

AtCoderで黄になるのが先だと思っていたのですが、やはりこどふぉの方がレート変動しやすく、先に暖色になりました。

Codeforcesの過去問を解くことによる精進はほとんどやったことがないです。でも問題の性質上もしかしたらこどふぉのほうが得意なのかもです。自分の英語力や生活リズムと相談しながらできる範囲でこれからは参加していけたらと思っています。でももちろん、AtCoderを最優先にしております。ABCがunratedになったことにより、ratedがとても少なくなりました。なので海外コンに本腰を入れる時期かもと思うなどしています。

AtCoder

AtCoder黄になりました!!!!!!!!

参加回数はもうすぐ200回、競プロ歴はもうすぐ5年になります。とても意義のある5年だったと思えます。純粋培養競プロerであり、初めは情報全般の知識もなく、AtCoderのアカウントの作り方すらわからない状況でした。ライバルで居続けてくれた高専時代のクラスメートたちには感謝しています。知り合いの明石高専出身者の中ではようやく一番になれました。単にまわりがやめただけですが、飽きっぽい自分自身がここまで1つのことを継続できたことが嬉しいです。

AtCoder黄色になるためにやったこと

shinchankosen.hatenadiary.jp

具体的な精進については上記記事の方が詳しいと思います。

AtCoder青は2020年7月になったので2年半たってます。その間なにをしたかを記事にしたいと思ってます。

なにもしていません、ただコンテストに出て復習しただけです。

というのは、AtCoder青になるまでにやったことが相当オーバーキルだったらしく、そのあと無精進で1800を超えました。しかし画像の通り、なんどもなんどもチャンスはあったのに黄色になれませんでした。一度目の山のHighestが1998です。そこから1840まで下がり、そのあとも1970まで上がって下がり、1997まで上がって下がり…を繰り返しました。

青になってから自分では精進したという感覚はほとんどないので先ほどのような書き方をしました。ですが、青になってからもよくバチャをやったり、過去問を解く以外のことをやっていたんだと思います。こどふぉもたまにやってました。なのでレートを維持できました。そして、さすがにここ数ヶ月、精進しました。毎日平均3時間はやっていたと思います。冬休みにラストスパートをかけ、1日10時間程度やりました。そして、ようやく黄色になれました。


というわけで、この数ヶ月の精進や、青になってからについて説明します。

mo-algorithm、牛ゲー、挿入DP、燃やす埋める、双対あたりでしょうか。毎度おなじみけんちょんさんの記事を使用させて頂きました。今回ははてなブログの方です。けんちょんさんいつもお世話になってます。ライブラリよく使わせていただいてます。 drken1215.hatenablog.com


  • たまにバチャをやってました

problemsのまよこんや、atcoder公式のバチャが主です。


  • 典型90問を埋めました

今思ったけどほぼこれでは。E869120さんありがとう…。


  • ABC, ARC, AGCなど、Ratedコンのdiff2200以下を埋めました。

やはり黄になるためには黄diffを解く必要があります。


  • Techful

受験期に暇つぶしでやってました(?)。 総合ランキング現在7位です。

やってたときはこんな感じです。

思うところ

コンテスト・精進

私は早解きは苦手で、1問でも多く解く方が自分に合っています。また、ペナルティが人より少ないと感じています。提出時もほぼ毎回入念なチェックをするなどしています。そこで発見できるミスもあったりします。ノーペナは大事です。

また、最近はABCよりARCやAGCの方が得意です。これは早解きが苦手なことと被るかもしれません。結局、どのコンテストかにかかわらず、無差別に出たらいいと思います(テスト前は出ない方がいい)。



青になってからも私がコンテストに出続け、精進を続けた精神的な理由には2人の赤コーダーの存在が大きいです。

  • tozangezanさん

www.youtube.com

この動画の、概要欄の言葉を貼り付けます。

競技プログラミングよりも役に立たないものの例として、競技プログラミングが役にたつかどうかというくだらないTwitter上の議論に何時間も参加することが挙げられます。あなたが競技プログラミングが役に立たないと言っている人に対して役に立った例を探してきてリプライしている時間に、本当に強い競技プログラマーは問題を解いているのです。」

私は現に競プロ以外のプログラミングが苦手ですし、まわりからも指摘をされることがあります。しかし、よく考えなくとも成功する人というのは1つのことに熱中し続ける人だと自己啓発本とかにも書いてたりしますよね、ここ5年くらいはそういうの読んでないけど。そもそも、学生時代部活動・サークル活動がんばってましたっていうガクチカと変わらないですし。

競技プログラミングは役にたたない → 辞める

という人は少なくないと思います。しかし、私の場合は競プロをやめたところで、アルゴリズムによる高速化などが使われないようなプログラミングに熱中できる自信がありません。競プロ辞めたところで他のことしないし、そうなるくらいなら競プロ続けたマシ、という理論で競プロを続けましょう。


  • のいみさん

2020年夏の競プロキャンプ(関西)にて、ratedがありました。しかし、私は出ませんでしたが、のいみさんに言われたことを今でも思い出します。

「目の前にRatedがあるのになんででないんですか?」

Ratedに出ないことにはレートは上がりませんし、実力も付きにくいのは事実だと思います。のいみさんがこの発言を冗談で言ったのか、それとも赤ともなれば本当にそういう心がけをしているのかはわかりませんが、この発言がなかったら私の入黄はあと1,2年遅いか、なるまでに競プロをやめていたかもしれません。


もちろんこの2人以外にもこれまで精進の助けになった方々がたくさんいます。本当にありがとうございました。競プロのおかげで数学力がついたし、おかげで今の大学にも入ることができました。

普段の生活への影響とその逆

精進以外の面

直接精進とは関係ないですが、競プロ関係のやってきたことがいくつかあります。

  • OUPC

onlinejudge.u-aizu.ac.jp

CのClockを作問しました。generatorとvalidatorを作ったり、そもそもgit使ったり、1問しか作ってないですがいい経験になったと思います。いい加減行列累乗以外の問題を作れるようにならないと…。

解説 ↓ qiita.com

AtCoder Jobsでは高速化で有名なF社に行きました。高専1年のころでしょうか、同じ高専の4つ上の先輩に紹介されました。そして4年くらいたって2022年の春くらいに申し込んで、面接を受け、夏に行ってきました。

競プロを仕事で生かせたという嬉しさがありました。また、業務で競プロを生かすためにはやはり業務の知識が必要で、gitlabを使用したり、ミーティングがあったりしました。メンターの方がAtCoder橙で、いろいろ吸収できる面もありました。

インターン生3人で自己紹介したら僕以外2人とも東大だった、こわい。

  • バイト

現在やっているうちの1つは、阪大で競プロerが多い某バイトです。そもそものpythonなど、まだ慣れないことが多いですが、gitなど他のバイトやインターンと共通する部分もあったりします。dockerは2回目なのになにもわかってないです()。そういえば満足に競プロができるようになったのも始めて1年半くらいたってからだったと思います。もうすぐ春休みですし余裕あればどんどんやって早く慣れたいですね。

不満とか

精進をしてなかったというより、できなかったと言いたいです。編入生なので3年生で取る単位は多くなります。今回(後期期末試験)もテストの半分は2年生の科目です。大学の授業というのは、科目数自体は高専より少なくなります。しかし、課題の量がかなり多くなりました。課題に追われて競プロができないときが多かったです。また、1人暮らしで家事を自分で行う必要があります。高専で寮生活を経験していましたが、やることの量が段違いです。

これから

青なったときにも同じようなこと言ったんですが、院試あるので勉強を…

となっているんですが結局出ると思います。今のところABCよりARCやAGCの方が得意です。また、Codeforcesを再開して赤目指します。精進量は落ちると思いますが自分のペースでやっていきたいです (むしろ精進量落ちてほしい、5年間やってようやく学業に支障がでてきた)。


ABCがunratedになったのでFA狙ったりしようかなと思ってます。私は早解きタイプではないのでかなり苦手なんですが、開始早々DとかFとか見ることになりそう。

あとがき

記事書くの遅くなりました。お待たせしました。

先日とあるLT会でけんちょんさんと4年ぶりに再会しました。前に会ったのは明石高専祭でしょうか。当時私は茶色コーダーで、会話も苦手でした。ある程度会話ができるようになり、黄色コーダーになって会うことができました。けんちょんさんが成長を感じてくれて嬉しかったです。

























競プロやりすぎて単位落としたかも

追記 : めっちゃぎりぎりフル単でした~~~!!!!!!!