SRM 735 MaxSquare 「よくある二分探索の変なことをやるやつ」

なんやこのテク...っていう気持ちになったので記事を書きます

http://community.topcoder.com/stat?c=problem_statement&pm=14929

問題の解説...https://www.topcoder.com/blog/single-round-match-735-editorials/

りんごさんの参考解説動画(ICPCの類似した問題)

https://youtu.be/agCN6bPxeE4?t=6052

https://youtu.be/agCN6bPxeE4?t=11979

問題の本質

数列Bが与えられる.
このときf(i,j) = (B[j] - B[i]) * (j - i + 1)の最大値を求めよ.

平面で考えてみる

横軸をindex,縦軸をBの値のと置くと、下のような図ができて

f:id:Kutimoti:20180831214244j:plain

この図でf(1,2)は、下の長方形の面積になります.'

f:id:Kutimoti:20180831214304j:plain

これの最大を求めたい...

最適な右上

ある頂点iを決めたとき、f(i,j)が最大になるjを「最適な右上」と呼ぶことにします.

左下になり得る頂点、右上になり得る頂点

こんな感じになりそう(実際なって証明ができるがなんとなくわかる)

f:id:Kutimoti:20180831214333j:plain

最適な右上が単調増加

もしこの図で

f:id:Kutimoti:20180831214358j:plain

頂点0の最適な右上が3

頂点1の最適な右上が2だとすると

f(0,2) < f(0,3) ==> ABCD < CDE ==> AB < E
f(1,3) < f(1,2) ==> DEFG < BDF ==> EG < B

足すと
ABEG < BE ==> AG < 0(は?)

これは矛盾

つまり

ある左下の頂点Lを決めたときの最適な右上をRとすると、Lより左側の頂点を左下としたときの最適な右上はRより左側、右側についても同様が成り立つ

f:id:Kutimoti:20180831214431j:plain

これを使うと,左下の頂点の区間[left,right),右上の頂点の区間を'[lo,hi)'とすると

(下のsolve関数を見たほうがいいかもしれない)

1.mid = (left + right) / 2番目の左下の頂点をLとする.

2.Lの最適な右上を調べ、indexをrとする.

3.答えを更新

4.[left,mid),[lo,r + 1)に分割して1.をする.

5.[mid + 1,right),[r,hi)に分割して1.をする.

これで答えがO(NlogN)で求まります(すごい)

Source

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);(i)++)
#define all(x) x.begin(),x.end()

class MaxSquare{
public:
  using P = pair<i64,i64>;
  vector<P> L,R;

  vector<P> normalize(vector<P> v){
    vector<P> ret;
    for(int i = 0;i < v.size();i++){
      while(ret.size() > 0 && ret[ret.size() - 1].second <= v[i].second){
        ret.pop_back();
      }
      ret.push_back(v[i]);
    }
    return ret;
  }

  vector<P> flip(vector<P> v){
    for(int i = 0;i < v.size();i++){
      v[i].second *= -1;
    }
    reverse(v.begin(),v.end());
    return v;
  }

  i64 solve(int left,int right,int lo,int hi){
    int mid = (left + right) / 2;
    int bestl = -1;
    i64 best = -1;
    for(int i = lo;i < hi;i++){
      i64 cur = (L[mid].first - R[i].first) * (L[mid].second - R[i].second);
      if(cur > best){
        best = cur;
        bestl = i;
      }
    }

    if(left < mid){
      best = max(best,solve(left,mid,lo,bestl + 1));
    }
    if(mid + 1 < right){
      best = max(best,solve(mid + 1,right,bestl,hi));
    }
    return best;
  }

  i64 getMaxSum(i64 n,i64 s,i64 q,i64 o,vector<i64> x,vector<i64> y){

    vector<i64> b(n);
    rep(i,0,n - 1){
      b[i] = (s / (1LL << 20)) % q + o;

      i64 s0 = (s * 621) % (1LL << 51);
      i64 s1 = (s * 825) % (1LL << 51);
      i64 s2 = (s * 494) % (1LL << 51);
      i64 s3 = (s *  23) % (1LL << 51);

      s = s3;
      s = (s * (1LL << 10) + s2) % (1LL << 51);
      s = (s * (1LL << 10) + s1) % (1LL << 51);
      s = (s * (1LL << 10) + s0 + 11) % (1LL << 51);
    }
    for(int i = 0;i < x.size();i++){
      b[x[i]] = y[i];
    }
    auto X = b;
    for(int i = 1;i < n;i++){
      b[i] += b[i - 1];
    }
    vector<P> B;
    B.push_back({-1,0});
    for(int i = 0;i < n;i++){
      B.push_back({i,b[i]});
    }
    L = flip(normalize(flip(B)));
    R = normalize(B);

    i64 ans = 2 * solve(0,L.size(),0,R.size());
    if(ans == 0){
      ans = 2 * X[0];
      for(int i = 0;i < n;i++){
        ans = max(ans , 2 * X[i]);
      }
    }
    return ans;
  }
};

AtCoder Regular Contest 074 E - RGB Sequence

https://beta.atcoder.jp/contests/arc074/tasks/arc074_c

解法

左から色を決めていくとする.

すでに塗った部分の色をすべて覚えておくことはできないので、情報量を落とさなければならない.

どうしよう?

ここで問題の性質である色の種類がxiであるについて考える.

区間に色を含んでいることはどうやってわかるだろう...?

これは,各色の一番右の場所を覚えておけば良い.

なので,i番目のマスを更新する際.i == rとなる与えられている区間[l,r]について,

遷移元の状態がx種類であるかどうかを見てやれば良い.

なので

  dp[i + 1][i + 1][g][b] += dp[i][r][g][b];
  //g,bについても同様に

である.

しかし、これでは間に合わない.

よく見ると,i = max({r,g,b})であるので,遷移を縮めることができる.

これでOK.

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);(i)++)

int N,M;
vector<int> L,R,X;
vector<int> ri[303];

i64 dp[303][303][303];
i64 MOD = 1e9 + 7;
int main(){
  cin >> N >> M;
  L.resize(M);
  R.resize(M);
  X.resize(M);
  rep(i,0,M - 1) cin >> L[i] >> R[i] >> X[i];
  rep(i,0,M - 1) ri[R[i]].push_back(i);
  dp[0][0][0] = 1;

  rep(r,0,N - 1){
    rep(g,0,N - 1){
      rep(b,0,N - 1){
        int next = max({r,g,b}) + 1;
        //red
        {
          bool ok = true;
          int MIN = min({g,b});
          int MAX = max({g,b});
          for(auto idx : ri[next]){
            int cnt = 1;
            if(MAX >= L[idx]) cnt++;
            if(MIN >= L[idx]) cnt++;
            ok = ok && cnt == X[idx];
          }
          if(ok){
            dp[next][g][b] += dp[r][g][b];
            dp[next][g][b] %= MOD;
          }
        }
        {
          bool ok = true;
          int MIN = min({r,b});
          int MAX = max({r,b});
          for(auto idx : ri[next]){
            int cnt = 1;
            if(MAX >= L[idx]) cnt++;
            if(MIN >= L[idx]) cnt++;
            ok = ok && cnt == X[idx];
          }
          if(ok){
            dp[r][next][b] += dp[r][g][b];
            dp[r][next][b] %= MOD;
          }
        }
        {
          bool ok = true;
          int MIN = min({g,r});
          int MAX = max({g,r});
          for(auto idx : ri[next]){
            int cnt = 1;
            if(MAX >= L[idx]) cnt++;
            if(MIN >= L[idx]) cnt++;
            ok = ok && cnt == X[idx];
          }
          if(ok){
            dp[r][g][next] += dp[r][g][b];
            dp[r][g][next] %= MOD;
          }
        }
      }
    }
  }

  i64 ans = 0;
  rep(i,0,N - 1){
    rep(j,0,N - 1){
      ans = (dp[N][i][j] + ans) % MOD;
      ans = (dp[i][N][j] + ans) % MOD;
      ans = (dp[i][j][N] + ans) % MOD;
    }
  }

  cout << ans << endl;
}

AtCoder Regular Contest 100 E - Or Plus Max

問題URL : https://beta.atcoder.jp/contests/arc100/tasks/arc100_c

問題

長さ2^Nの整数列A(0-indexed)がある.

1 <= K <= 2^N - 1を満たすすべての整数 K について, 次の値を求める.

0 <= i < j <= 2^N - 1,(i or j) <= K のとき, A_i + A_jの最大値を求めよ.

問題を見て思ったこと

(i or j) <= K から i < j <= K であることがわかる.

(i or j) <= Kなので,うまくbitDPをしそう...

考察

入力例3について考えてみます.

次のように,最大値を2番目まで持つことでうまくやることができます.

f:id:Kutimoti:20180701233634j:plain

i = 0 のときの MAX1st,MAX2nd を作る.

f:id:Kutimoti:20180701233704j:plain

ここで,最大値と同時にiの値も記録するのが大事です(後で説明します)

K = 1のときの値を求める

f:id:Kutimoti:20180701233735j:plain

K = 1のときは j = 0,1 が選べるので,MAX1st[i]の値は75に,MAX2nd[i]の値は26になります.

ここでMAX1st[i] + MAX2nd[i]を取ると,K = 1のときの答えが得られます.

K = 2のときの値を求める.

f:id:Kutimoti:20180701233809j:plain

K = 2のときは j = 0,2 が選べるので,MAX1st[i]の値は75に,MAX2nd[i]の値は45になります.

ここでMAX1st[i] + MAX2nd[i]を取ると,K = 1のときの答えが得られます.

K = 3のときの値を求める.

f:id:Kutimoti:20180701233924j:plain

ここが大事です.

K = 3のときは j = 0,1,2が選べますが,

j = 0 を見る必要はあるでしょうか?ないですね.

なぜなら,j = 0 の値は j = 1,2 ですでに評価されています(その結果,MAX1stが75になっている)

なので,見るべきは K = 3からビットを一つづつ消した,j = 1,2だけでOKです.

また,青色の矢印がバツされています.なぜでしょう?

これはi < jの条件です.重複を防いでいます.これのためにMAX2ndを用意しています.

これを繰り返すことで (i or j) == K のときの値を計算できます.

(i or j) <= K

(i or j) == K について考えていたので,後は今までの最大値を取るだけでOKです.

source code

resとans要らない(草)

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);(i)++)
#define all(x) x.begin(),x.end()

int N;
vector<i64> A;

vector<i64> ans;
vector<i64> MAX[2];
vector<i64> mi[2];
vector<i64> res;
int main(){
  cin >> N;
  A.resize(1 << N);
  ans.resize(1 << N,0);
  MAX[0].resize(1 << N,0);
  MAX[1].resize(1 << N,0);
  mi[0].resize(1 << N,0);
  mi[1].resize(1 << N,0);
  res.resize(1 << N,0);
  rep(i,0,(1 << N) - 1) cin >> A[i];
  MAX[0][0] = A[0];
  mi[0][0] = 0;
  ans[0] = A[0];
  res[0] = A[0];
  int cnt = 0;
  rep(s,1,(1 << N) - 1){
    vector<pair<i64,i64>> vec;
    vec.push_back({A[s],s});
    rep(i,0,N){
      if(s & (1 << i)){
        vec.push_back({MAX[0][s & ~(1 << i)],mi[0][s & ~(1 << i)]});
        vec.push_back({MAX[1][s & ~(1 << i)],mi[1][s & ~(1 << i)]});
      }
    }
    sort(all(vec));
    //重複削除
    vec.erase(unique(all(vec)),vec.end());
    //最大値なので
    reverse(all(vec));
    if(vec.size() >= 2){
      MAX[0][s] = vec[0].first;
      mi[0][s] = vec[0].second;
      MAX[1][s] = vec[1].first;
      mi[1][s] = vec[1].second;
      ans[s] = MAX[0][s] + MAX[1][s];
    }
    //これ多分要らない
    else{
      MAX[0][s] = vec[0].first;
      mi[0][s] = vec[0].second;
      ans[s] = MAX[0][s];
    }
    res[s] = max(ans[s],res[s - 1]);
    cout << res[s] << endl;
  }
}

うまく説明するのが難しいなぁ...

Codeforces 1000B Light It Up

http://codeforces.com/problemset/problem/1000/C

問題概要

時間 0,a1,a2,...,aN,M のタイミングで明かりがON,OFFを繰り返す.

ここで最大1個,タイミングを増やすことができる.

明かりがついている時間を最大化せよ.

解法

onの区間にXを挿入する

a_i-2 [off] a_i-1 [on] a_i [off] a_i+1

のような区間

a_i-2 [off] a_i-1 [on] X [off] a_i [on] a_i+1

とすることを考えると,このときの明かりがついている時間の合計は,Xを挿入する前の状態を考えて

(a[i]より左側のonの時間) - 1 + (a[i]より右側のoffの時間)

となる.なぜなら,なるべくonの区間を長くしようとするとX = (a_i) - 1となるからである

offの区間にXを挿入する

a_i-2 [on] a_i-1 [off] a_i [on] a_i+1

のような区間

a_i-2 [on] a_i-1 [off] X [on] a_i [off] a_i+1

とすることを考えると,このときの明かりがついている時間の合計は,Xを挿入する前の状態を考えて

(a[i - 1]より左側のonの時間) + (a[i - 1]より右側のoffの時間) - 1

となる.なぜなら,なるべくonの区間を長くしようとするとX = (a_i - 1) - 1となるからである

Xの挿入する区間がonかoffかはindexの偶奇によって決まるので,それを実装してやれば良い.

source code

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);(i)++)

int N;
i64 M;
vector<i64> A;

int main(){
  cin >> N >> M;
  A.resize(N + 2);
  A[0] = 0;
  rep(i,1,N) cin >> A[i];
  A[N + 1] = M;

  vector<i64> on;
  vector<i64> off;
  on.push_back(0);
  off.push_back(0);
  rep(i,1,N + 1){
    if(i % 2 == 1){
      on.push_back(A[i] - A[i - 1] + on.back());
      off.push_back(off.back());
    }
    else{
      off.push_back(A[i] - A[i - 1] + off.back());
      on.push_back(on.back());
    }
  }

  i64 ans = on.back();

  rep(i,1,N){
    if(i % 2 == 1){
      ans = max(ans , on[i] - 1 + off.back() - off[i]);
    }
    else{
      ans = max(ans , off.back() - off[i - 1] - 1 + on[i]);
    }
  }
  cout << ans << endl;
}

こういう問題をきれいに早く実装したいなぁ...

bitDPでの集めるDPと配るDPについて

こんなツイートが

このときは「わかる」ってなってたんですけど

いざ問題を解いてみるとそんなこと無いな,なんでだろう,みないな記事です

以下の問題のネタバレを含みます 気をつけてください

https://yukicoder.me/problems/no/357

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0263

考える問題1

https://yukicoder.me/problems/no/357















空白













集めるDP

で書くとこうなる

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

int N,M;

i64 score[14][14];

i64 dp[1 << 14];
int main(){
  cin >> N >> M;
  for(int i = 0;i < M;i++){
    i64 a,b,c;
    cin >> a >> b >> c;
    score[a][b] = c;
  }

  for(int s = 1;s < (1 << N);s++){
    for(int p = 0;p < N;p++){
      int t = s & ~(1 << p);
      if(t == s) continue;
      i64 res = 0;
      for(int i = 0;i < N;i++){
        if(t & (1 << i)){
          res += score[i][p];
        }
      }
      dp[s] = max(dp[s],dp[t] + res);
    }
  }

  cout << dp[(1 << N) - 1] << endl;
}

集めるbitDPは

int t = s & ~(1 << p);

としてやることでp番のアイテムを置く前の状態を表現できる

このとき

if(t == s) continue;

とするのが重要で,置く前の状態になっているかを確認する

配るDP

で書くとこうなる

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

int N,M;

i64 score[14][14];

i64 dp[1 << 14];
int main(){
  cin >> N >> M;
  for(int i = 0;i < M;i++){
    i64 a,b,c;
    cin >> a >> b >> c;
    score[a][b] = c;
  }

  for(int s = 0;s < (1 << N);s++){
    for(int p = 0;p < N;p++){
      int t = s | (1 << p);
      if(t == s) continue;
      i64 res = 0;
      for(int i = 0;i < N;i++){
        if(s & (1 << i)){
          res += score[i][p];
        }
      }
      dp[t] = max(dp[t],dp[s] + res);
    }
  }

  cout << dp[(1 << N) - 1] << endl;
}

配るbitDPは

int t = s | (1 << p);

としてやることでp番を置いたあとの状態を表現できる

if(t == s) continue;

も同様である

ここはあんまり差が無い

まあなんとかなるかなぁみたいな

本題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0263
















もち



























                                                                                                              

遷移

i回目の点灯の前の状態をstateとします

するとi回目の点灯があったあとはstate | A[i]という状態になります

その後、プレイヤーがjのパターンでボタンを押すと(state | A[i]) & ~B[i]という状態になります

このとき押したボタンの数は(state | A[i]) & B[i]のビットの立っている数です

つまり遷移は

dp[i + 1][(s | A[i]) & ~(B[j])] = 
        max(dp[i + 1][(s | A[i]) & ~(B[j])] , 
            dp[i][s] + __builtin_popcount((s | A[i]) & B[j]));

これは配るDPですね

集めるDPは?

遷移が思いつきにくい

なんで?

ゲームはすすめるイメージが強いのかなぁ...

でもしっかり配るDPでできたし、こっちのほうが素直

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);(i)++)
 
int N;
int C;
vector<i64> A,B;
 
int dp[31][1 << 16];
 
int solve(){
 
  rep(i,0,30){
    rep(j,0,(1 << 16) - 1) dp[i][j] = -1e9;
  }
  dp[0][0] = 0;
  cin >> N >> C;
  if(N == 0 && C == 0){
    return 0;
  }
  A.assign(N,0);
  B.assign(C,0);
  rep(i,0,N - 1){
    rep(j,0,15){
      int a;
      cin >> a;
      A[i] += a * (1LL << j);
    }
  }
  rep(i,0,C - 1){
    rep(j,0,15){
      int a;
      cin >> a;
      B[i] += a * (1LL << j);
    }
  }
 
  rep(i,0,N - 1){
    rep(s,0,(1 << 16) - 1){
      rep(j,0,C - 1){
        auto & to = dp[i + 1][(s | A[i]) & ~(B[j])];
        to = max(to , dp[i][s] + __builtin_popcount((s | A[i]) & B[j]));
      }
    }
  }
 
  int ans = 0;
  rep(s,0,(1 << 16) - 1){
    ans = max(ans,dp[N][s]);
  }
 
  cout << ans << endl;
  return 1;
}
 
int main(){
  while(solve());
}

まだ議論の余地がアリそうですね...(気分っていうのもあるかもしれない)

AtCoder 天下一プログラマーコンテスト0216予選A D グラフィカルグラフ

chokudaiしゃんに投げられたので解きましたー

問題

https://tenka1-2016-quala.contest.atcoder.jp/tasks/tenka1_2016_qualA_d

いわゆる構築

解法

常に最高効率で構築するのはとても大変

無駄があったり制約を満たさない解法であっても、必ず成立させられる構築方法を考えるのはとても重要

今回の場合であれば、「点の位置を必ず辺に到達できないようにする」ことで達成できるので

2^n >= 2^(n-1) + 2^(n-2) + ... + 1

を使って、

辺の長さを2^n,2^(n-1),2^(n-2)というように変化させることで

辺が交差しないように構築できます

が,H,W<=100を達成できません

これは座標圧縮をすることで解決できます

コード

https://tenka1-2016-quala.contest.atcoder.jp/submissions/2702775

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);(i)++)

vector<vector<int>> G;

i64 X[100];

i64 Y[100];

int dx[] = {1,-1,0,0};
int dy[] = {0,0,1,-1};

int vis[100];

void rec(int v,int n,int before_cnt){
  vis[v] = 1;
  int cnt = -1;
  for(int to : G[v]){
    if(vis[to]) continue;
    cnt++;
    if(cnt == (before_cnt ^ 1)) cnt++;
    X[to] = X[v] + dx[cnt] * (1LL << n);
    Y[to] = Y[v] + dy[cnt] * (1LL << n);
    rec(to,n - 1,cnt);
  }
}

char ans[100][100];

void rec2(int v,int n,int before_cnt){

  ans[X[v]][Y[v]] = v + 'A';
  vis[v] = 1;
  int cnt = -1;
  for(int to : G[v]){
    if(vis[to]) continue;
    int ddx = (X[to] - X[v] > 0 ? 1 : -1);
    int ddy = (Y[to] - Y[v] > 0 ? 1 : -1);
    if(X[to] == X[v]) ddx = 0;
    if(Y[to] == Y[v]) ddy = 0;
    for(int x = X[v] + ddx,y = Y[v] + ddy;x != X[to] || y != Y[to];x += ddx,y += ddy){
      ans[x][y] = (ddx != 0 ? '|' : '-');
    }
    rec2(to,n - 1,cnt);
  }
}

int main(){

  rep(i,0,99){
    rep(j,0,99) ans[i][j] = '.';
  }
  int N;
  cin >> N;
  G.resize(N);

  rep(i,0,N - 2){
    char c,d;
    cin >> c >> d;
    int a,b;
    a = c - 'A';
    b = d - 'A';

    G[a].push_back(b);
    G[b].push_back(a);
  }

  rec(0,N,10);
  vector<i64> xs,ys;
  rep(i,0,N - 1){
    xs.push_back(X[i]);
    ys.push_back(Y[i]);
  }

  sort(xs.begin(),xs.end());
  sort(ys.begin(),ys.end());
  xs.erase(unique(xs.begin(),xs.end()),xs.end());
  ys.erase(unique(ys.begin(),ys.end()),ys.end());

  rep(i,0,N - 1){
    X[i] = lower_bound(xs.begin(),xs.end(),X[i]) - xs.begin();
    Y[i] = lower_bound(ys.begin(),ys.end(),Y[i]) - ys.begin();
    X[i] *= 2;
    Y[i] *= 2;
    vis[i] = 0;
  }

  rec2(0,N,10);

  cout << 100 << " " << 100 << endl;
  rep(i,0,99){
    rep(j,0,99){
      cout << ans[i][j];
    }
    cout << endl;
  }
}

感想

・2進数ってすごいなぁ...

・制約以上のを考えたときは圧縮を考える

LinuxにC++を快適に書く環境を作る(Visual Studio Code + cquery)

経緯

結構前にclang Adaptaを使ったvscodeの環境構築方法の記事を書きました

kutimoti.hatenablog.com

が、これ最悪ですね???

・重い ・エラーチェック遅い ・重い ・VSじゃん()

LSPのcqueryを使えばバク速です!!!

(Windowserはおとなしくclangdを使いましょう)

(MacOSの記事も書きたいけど環境がない...)

僕の環境構築テスト環境

Xubuntuなのでaptを乱用していますが、それそれ読み替えれば大丈夫だと思います

VSCodeインストール

code.visualstudio.com

ここから自分のプラットフォームに合わせてインストールしましょう

Archの方はAUR https://aur.archlinux.org/packages/visual-studio-code-bin/ からインストールしてください

cqueryのビルド

sudo apt-get install clang clang-tools llvm llvm-6.0-tools libclang-6.0-dev

を入れておけばできるはずです

kutimoti.hatenablog.com

これと同じように進めます

僕はホームディレクトリでやりました

git clone https://github.com/cquery-project/cquery --single-branch --depth=1
cd cquery
git submodule update --init
./waf configure --variant=system --llvm-config=/usr/bin/llvm-config build

ビルドされたcqueryにパスを通します

~/.profileにこれを書き加える

PATH="$HOME/cquery/build/system/bin:$PATH"

vscodeセットアップ

vscodeは基本フォルダを開いて作業します(Atomにも同じようなのがあるはず)

ディレクトリでcode .とコマンドを打つと、vscodeがそのディレクトリを開いてくれます

C++を書く用のディレクトリでcode .とやってみてください(僕は適当に~/C++/でやりました)

左のバーの一番したをクリックをすると拡張機能を選ぶことができます

f:id:Kutimoti:20180302100535p:plain
Extension

今回入れるのはC/C++cqueryです

それぞれC++,cqueryと検索欄で打つと出てくるのでinstallを押してreloadをします

これで完了です!!

コードを書く

フォルダを開いていないとエラーチェックとか補完とか出してくれないので注意です!

使い方

これについてはまた書こうかなと思ってます><