LoginSignup
2
1

More than 3 years have passed since last update.

AtCoderで緑を目指す自分用備忘録

Last updated at Posted at 2020-10-06

TL;DR

1:使ってるマクロ
2:使ってるスニペット
3:やる前の準備
4:ABC問題を解くときの注意事項
5:勉強用の記事

使ってるマクロ

マクロには大きく分けて2つの使い方があります。
1、よく使うコードを省略
2、忘れがちなコードの登録

// ---------------- 標準ライブラリ ------------------- //
#include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;
/* ----------------- よく使う ------------------------ */
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define rrep(i,n) for(int i = 1; i <= (n); ++i)
#define drep(i,n) for(int i = (n)-1; i >= 0; --i)
#define srep(i,s,t) for (int i = s; i < t; ++i)
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()  // 右から読む.reverse
#define sortu(x) sort((x).begin(),(x).end())
#define sortd(x) sort((x).begin(),(x).end(), greater<int>())
#define pb push_back
#define eb emplace_back
#define sz(x) (int)(x).size()
using ll = long long int;
using vi = vector<int>;
using vl = vector<ll>;
using P = pair<int,int>;
#define fi first
#define se second
#define mp make_pair
#define mset(m,v) memset(m,v,sizeof(m))
using Graph = vector<vector<int>>;
#define v(T) vector<T>
template<typename T>istream& operator>>(istream&i,v(T)&v){rep(j,sz(v))i>>v[j];return i;}  // cin>>v 配列に代入
template<typename T>ostream& operator<<(ostream&o,const v(T)&v){if(sz(v))o<<join(v);return o;}  // cout<<v 配列を出力
template<typename T1,typename T2>istream& operator>>(istream&i,pair<T1,T2>&v){return i>>v.fi>>v.se;}
template<typename T1,typename T2>ostream& operator<<(ostream&o,const pair<T1,T2>&v){return o<<v.fi<<","<<v.se;}  // ,に注意
template<typename T>bool mins(T& x,const T&y){if(x>y){x=y;return true;}else return false;}
template<typename T>bool maxs(T& x,const T&y){if(x<y){x=y;return true;}else return false;}
template<typename T>ll suma(const v(T)&a){ll res(0);for(auto&&x:a)res+=x;return res;}
/*----------------- 定数 ---------------------*/
const ll LINF = 1001002003004005006ll;
const int INF = 1001001001;
const int MOD1 = 1e9+7;
const int MOD9 = 998244353;
const int Max_T = 200005;
/*----------------- 出力 ---------------------*/
#define shousuu cout << fixed << setprecision(15)
#define dame0 { puts("0"); return 0;}  // ; 含む
#define dame1 { puts("-1"); return 0;}
#define damen { puts("No"); return 0;}
#define yn {puts("Yes");}else{puts("No");}
#define outa cout << ans << endl;
#define out(x) cout << x << endl;
#define r0 {return 0;}
/*--------------- 忘れがち -------------------*/
#define ul(x) x^=32  // 大文字小文字を逆にする
#define dup(x,y) ((x+y-1)/y)  // 切り上げ
/*--------------- 二分探索 -------------------*/
#define posi(x,v) *((lower_bound(x.begin(),x.end(),v)))
#define posl(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())  // v未満の個数 (keyを前に挿入(iterはkeyより大))
#define posl2(x,v) (x.end()-lower_bound(x.begin(),x.end(),v))   // v以上の個数
#define posu(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())  // v以下の個数 (keyを後ろに挿入)
#define posu2(x,v) (x.end()-upper_bound(x.begin(),x.end(),v))   // vより大きい個数
#define bs(x,v) (binary_search(x.begin(),x.end(),v))
//-------------------Tips-----------------------//
//mins(ans,now);  ansに最小値が入る
//if(max(ans,now)) ansが小さければ更新して実行
//ll sum = suma(a);
//int a[33][4];
//vi a{1,2,3};
// vvi dp(n+1, vi(3));  n+1行、3列
bool flg = false;
// flg = true;

使ってるスニペット

長すぎてマクロにできないものはスニペットにします。
特に入力系のスニペットは大活躍するので、入れるのをオススメします。


{
    // ----------------- 入力 --------------------------- //
    "cin_vector_int":{
        "prefix": "cinv",
        "body":[
            "vector<int> $1($2); rep(i, $2) cin >> $1[i];",
            "$3"
        ],
        "description": "vector<int>の受取"
    },
    "cin_vector_int-":{
        "prefix": "cinv-",
        "body":[
            "vector<int> $1($2); rep(i, $2) { cin >> $1[i]; $1[i]--;}",
            "$3"
        ],
        "description": "vector<int>の受取 -1"
    },
    "cin_vector_int2":{
        "prefix": "cinv2",
        "body":[
            "vector<int> $1($3),$2($3); rep(i, $3) cin >> $1[i] >> $2[i];",
            "$4"
        ],
        "description": "vector<int>の受取2"
    },
    "cin_vector_int3":{
        "prefix": "cinv3",
        "body":[
            "vector<int> $1($4),$2($4),$3($4); rep(i, $4) cin >> $1[i] >> $2[i] >> $3[i];",
            "$5"
        ],
        "description": "vector<int>の受取3"
    },
    "cin_string":{
        "prefix": "cins",
        "body":[
            "string s; cin >> s;",
            "$1"
        ],
        "description": "stringの受け取り"
    },
    "cin_int3":{
        "prefix": "cin3",
        "body":[
            "int $1, $2, $3; cin >> $1 >> $2 >> $3;",
            "$4"
        ],
        "description": "intの受取3"
    },
    "cin_int2":{
        "prefix": "cin2",
        "body":[
            "int $1, $2; cin >> $1 >> $2;",
            "$3"
        ],
        "description": "intの受取2"
    },

    // ----------------- 省略 --------------------------- //
    "ruisekiwa0":{
        "prefix": "ruiseki0",
        "body":[
            "vector<ll> sum($1);",
            "rep(i,$1) {",
                "\tif(i==0) sum[i] = $2[i];",
                "\telse sum[i] = $2[i] + sum[i-i];",
            "}"
        ],
        "description": "累積和0"
    },
    "ruisekiwa1":{
        "prefix": "ruiseki1",
        "body":[
            "vector<ll> sum($1+1); rep(i,$1+1) sum[i+1] = $2[i] + sum[i];"
        ],
        "description": "累積和+1"
    },
    "next_permutation":{
        "prefix": "nextp",
        "body":[
            "do{",
            "$2",
            "}while(next_permutation($1.begin(), $1.end()));"
        ],
        "description": "next_permutation"
    },
    "bit_allsearch":{
        "prefix": "bit",
        "body":[
            "rep(i,(1<<n)){  // v[j]に対して操作をする",
            "\t//rep(j,n) if((i>>j)&1){  // iのj番目のbitが1なら……",
            "\t\t$1",
            "\t}",
            "}"
        ],
        "description": "bit全検索"
    },

    // ---------------  Key Algorithms  --------------------  //
    "find_prime_number": {
        "prefix": "isPrime",
        "body": [
            "bool is_prime(ll N) {",
            "\tif (N == 1) return false;",
            "\tfor (ll i = 2; i * i <= N; ++i) {",
            "\t\tif (N % i == 0) return false;",
            "\t}",
            "\treturn true;",
            "}",
        ],
        "description": "finding prime number"
    },
    "count_divisors": {
        "prefix": "cntdivide",
        "body": [
            "ll cnt_div(ll n) {",
            "\tll cnt = 1;",
            "\tfor (ll i = 1; i * 2 <= n; ++i) {",
            "\t\tif (n % i == 0) cnt++;",
            "\t}",
            "\treturn cnt;",
            "}",
        ],
        "description": "finding prime number"
    },

    "gcd": {
        "prefix": "gcd",
        "body": ["int gcd(int a, int b) {", "\treturn a ? gcd(b, a%b) : a;", "}"],
        "description": "Greatest Common Divisor"
    },

    "lcm": {
        "prefix": "lcm",
        "body": ["int lcm(int a, int b) {", "\treturn a / gcd(a, b) * b;", "}"],
        "description": "Least Common Multiply"
    },

    "digit_sum": {
        "prefix": "digitsum",
        "body": [
        "int digit_sum(ll n) {",
        "\tint res = 0;",
        "\twhile(n > 0) {",
        "\t\tres += n%10; //桁和",
        "\t\tres++; //桁数",
        "\t\tn /= 10;",
        "\t}",
        "\treturn res;",
        "}"
        ],
        "description": "sum of all digits"
    },

}

やる前の準備

1:VSCodeは30分前に立ち上げる

updateが必要な時があるので、事前にすませておく。
終わったら一度プログラムを走らせておく(最初は時間がかかるから)。

2:ノートとペンを用意する

数学的な問題を解くには下書きが必須。
雑紙ではなく、きちんとしたノートを使う。
問題が解けなかった時に見返すと、自分が何を見落としてたかはっきりする。

3:コピペを用意する

貼り付けるだけで正解する魔法のコード。検索しやすい題をつける。

ABCD各問題への対策

A問題

for文を使わない

A問題はfor文なしで解けます。
入力は最大で4文字なので、if文を列挙しても時間はかかりません。
例題:ABC175A
↑ Rが何回続いたのかを判定する問題です。if文を使えば、Rが続いた回数で場合分けできます。

切り上げ

覚え方は「切って上げる」。-1で切って、割る数で上げる。覚えるのが面倒ならマクロを作りましょう。
例題:ABC157A
Q:Nページの書類を両面印刷すると、最小で何枚の紙が必要か

//ans = (N-1+2)/2;
#define dup(x,y) (((x)+(y)-1)/(y))
ans = dup(n,2);

大きいほうを選ぶときは、ifよりmax

//if(a > b) ans = a;  // コードが長いです。
//else ans = b;       // コードが長いです。
ans = max(a,b);  // 1行でかけます。

Yes,Noの出力はマクロ

#define yn {puts("Yes");}else{puts("No");}
if(a >= 30) yn;  // 入力が30以上ならYes。未満ならNo。

B問題

小数点

小数点は誤差の温床。不要な割り算は使わないようにしましょう。掛け算にすればOKです。

//if(sqrt(a*a + b*b) == c)  //小数が出る
if(a*a + b*b == c*c)  // 小数が出ない

小数を出力する問題は桁数に注意しましょう。多めに出力する分には問題ないので、どーんと大きくいきましょう。「正しい値との絶対誤差または相対誤差が 10^(−9) 以下であれば正解とみなされる」なら、15桁くらい出しておきましょう。
ギリギリを狙うとWAが出るので注意。

#define shousuu cout << fixed << setprecision(15);
shousuu;  // 以降の出力が小数点以下15桁になる。

オーバーフロー

数が大きくなりそうなら、intではなくlonglongを使いましょう。マクロを使うとllで省略できます。
llでもオーバーフローするなら、割り算にしましょう。
例題:ABC169B

//ans *= a;  // そのまま掛け算するとオーバーフローする場合は……
const ll LINF = 1001002003004005006ll;
if(ans < LINF / a) ans *= a;  // オーバーフローしないかチェックしてから、掛け算をする。

C問題

コーナーケースを確認する。

例題が全部通っても過信してはいけない。

超便利なset

setは2つの機能を持っています。
・重複した値の削除
・昇順ソート
「同じ要素があるか答えよ」という問題はもちろんですが「条件を満たす数を列挙せよ」という問題にも役立ちます。例えば「Nの約数を列挙せよ」という問題の場合、通常なら重複をif文で除外して昇順ソートが必要ですが、setなら一発です。

重複なしループ

例えば「異なる数や点を3つ選び、条件を満たしているものの個数を求める」といった問題に使えます。

rep(i,n) rep(j,i) rep(k,j)

解けなかったらD問題へ

CよりDが簡単なこともあります。DよりEが簡単なときもあります。
(自分はまだ一度も体験してませんが)

勉強用の記事

Visual Studio Codeで競プロ環境構築
AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~
レッドコーダーが教える、競プロ・AtCoder上達のガイドライン【初級編:競プロを始めよう】
レッドコーダーが教える、競プロ・AtCoder上達のガイドライン【中級編:目指せ水色コーダー!】

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1