pyenvを使った仮想環境構築

日々生活していると突然以下のように環境構築を求められることがあります

以下のパッケージを使用するので、予め環境構築をお願いします。

Python==3.5.2

IPython==5.?.?

numpy==1.?.?

pandas==0.?.?

matplotlib==?.?.?




おーん( ´_ゝ`)




今後のためにも自分がどのようにしたか記載しておきます

今回はBBQという名前のフォルダ以下に環境を構築したいとして進めていきます

ここを参考にすればこのページを読む必要はなさそう

qiita.com



mkdir BBQ #フォルダ作成

cd BBQ #移動

pyenv install 3.5.2 #pyenvでpython3.5.2をインストール

pyenv local 3.5.2 #pyenvでインストールしたバージョンのpythonを使うように指定

pyenv virtualenv 3.5.2 test #3.5.2を使用してテスト環境を作成

pyenv local test

activate test #テスト環境に移行

#ここではcustom.listファイルに必要なパッケージが書かれているものとする
#numpy==1.?.?
#pandas==0.?.?
.....


pip install -r custom.list




この環境下でさらにJupyterも使いたい!

そんな時に参考にしたのがこちらのページ

qiita.com

pip install ipykernel


ipython kernel install --user --name=test --display-name=test


jupyter notebook




f:id:inaba00032:20180831172830p:plain




最新でない特定のバージョンのライブラリをインストールした環境が構築できました

Atcoder Express2

今回はソースコードだけ(コード内にメモ用解説があります)

N,M,Q=map(int,input().split())
 
 
 
answer=[[0]*N for i in range(N)]
for i in range(M):
  L,R=map(int,input().split())
  answer[N-L][R-1]+=1
 
for i in range(1,N):
  answer[0][i]+=answer[0][i-1]
  answer[i][0]+=answer[i-1][0]
  
print(answer[0])
for i in range(1,N):
  for j in range(1,N):
    answer[i][j]+=answer[i-1][j]
    answer[i][j]+=answer[i][j-1]
    answer[i][j]-=answer[i-1][j-1]
for i in range(Q):
  p,q=map(int,input().split())
  print(answer[N-p][q-1])
 
'''
#図のような正方形で累積和を考える
こう取ればLが1でRが10の時(一番右下の時)全ての区間が入るように和を計算できる
 
  1 2 3 4 5 6 7 8 9 10 ←R
10                   1
9
8
7                 1
6           1 1
5               1
4         1   2
3
2                 1
1           1

L
 
例えば、L,R=5,8の電車はもちろん5,8の区間に含まれている。
ここで5,8の区間に含まれる電車の数を考えると5,7の電車や6,8の電車は含まれている...
という風に考えると累積和を取れる
ここで、6,7の区間に含まれる電車の数は5,7と6,8を数えることで2回計算されているのでマイナスする
 
 
'''

Wekaによるデータの離散化(Discretize)

離散化

--

離散化では、連続的な数値の属性を離散した属性に分類します。

例えば、1年に読んだ本の冊数について以下のように人数がいたとします。

1冊:5人 2冊:5人 10冊:10人 20冊:12人 40冊:3人 47冊:1人 50冊:2人

ここで、1年に読んだ本の冊数が40冊以上の人を読書家と呼べば、下記のような属性に落とし込めます。

読書家でない:32人 読書家:6人

厳密には違うかもしれませんが、私の中では上記のように捉えています。

(何かあればコメント下さい!)

Wekaの前処理

--

f:id:inaba00032:20180721162251p:plain

フィルターから離散化を選択

f:id:inaba00032:20180721162516p:plain

Discretizeのオプションについては以下のURLを参考にできます。 http://weka.sourceforge.net/doc.dev/weka/filters/unsupervised/attribute/Discretize.htmlweka.sourceforge.net

-Rオプションでは関数を適用する列を指定しており、デフォルトのfirst-lastでは全ての列に適用されます。

以下のように各クラスについてDiscretizeを行います。

f:id:inaba00032:20180722020235p:plain

されました。

【AGC 026】C.String Coloring

問題文


長さ 2N の,英小文字のみからなる文字列 S が与えられます。

S の各文字を赤色か青色かに塗り分ける方法は22N 通りありますが,

このうち以下の条件を満たす塗り分け方は何通りですか?

  • 赤色に塗られた文字を左から右に読んだ文字列と,

    青色に塗られた文字を右から左に読んだ文字列が一致する

制約


  • 1≤N≤18
  • Sの長さは2Nである
  • Sは英小文字のみからなる

考え方


コンテスト中には全く分からなかったので以下のコードを参考に考えました。 https://beta.atcoder.jp/contests/agc026/submissions/2864808

itertools.product関数

#以下二つは同じ結果
print(list(product(range(3),repeat=3)))
print(list(((x,y,z) for x in range(3) for y in range(3) for z in range(3))))

[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), 
(1, 0, 0), (1, 0, 1), (1, 0, 2),(1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), 
(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2),(2, 2, 0), (2, 2, 1), (2, 2, 2)]

この関数を使って{0,1}のビットを用いて左側半分、右側半分についてそれぞれ文字列を区分する。

  • N=4,S=cabaacbaにおいて左側半分を区別する例
from collections import Counter
from itertools import product

N=int(input())
S=list(input())

bit=list(product(range(2),repeat=N)) #この例ではN=4なので、(0,0,0,0)~(1,1,1,1)の16パターン
leftlist=[]

for i in range(len(bit)):
  red=''
  blue=''
  for j in range(N):
    if bit[i][j] == 1:
      red+=S[j]
    else:
      blue+=S[j]
  leftlist.append("".join(red + "|" + blue))
left=Counter(leftlist)
print(left)    

Counter({'cba|a': 1, 'cb|aa': 1, 'ca|ab': 1, 'caa|b': 1, '|caba': 1, 'a|cba': 1, 'caba|': 1, 'ab|ca': 1, 
'ba|ca': 1, 'aba|c': 1, 'aa|cb': 1, 'cab|a': 1, 'ca|ba': 1, 'a|cab': 1, 'c|aba': 1, 'b|caa': 1})
#それぞれの分け方について、何通りあるかが表示される。この例では全て1回しか出てこない値は全て1

例えば、タプルの一つ目に出ている,

'cba|a': 1について考えてみると下のような状態

cabaacba ×この時は題意を満たすように塗れない

'ca|ab': 1について考えてみると下のような状態

cabaacba

下のように塗ると題意を満たします 

cabaacba

文字列の右側の塗り方をみると、ac|ba(blue+red)になっている。

左側はca|ab(red+blue)...(ここで何かに気付く)

文字列を逆側から考えると右半分についても、ca|ab(blue+red)

よって、左側半分と右側半分に対して色塗りの組み合わせが同じものを数え上げれば良いです。

左半分の青と右半分の赤は読む時は共に逆向きなので直感的に変に感じるかもしれないことに気をつけて下さい。

ソースコード


from collections import Counter
from itertools import product
 
N=int(input())
S=list(input())
S_rev=list(reversed(S[N:])) #右側から読んだ右半分の文字を考える
 
 
leftlist=[] #左半分の分け方の組み合わせを格納
rightlist=[] #右半分について同様
 
for bit in product(range(2),repeat=N):
  #左半分、右半分について赤と青に塗り分ける
  red_left='' 
  blue_left=''
  red_right=''
  blue_right=''
  for j in range(N):
    if bit[j] == 1:
      red_left+=S[j] #bitに1が立っているところを赤に
      blue_right+=S_rev[j]
    else:
      blue_left+=S[j]
      red_right+=S_rev[j]
  leftlist.append("".join(red_left + "|" + blue_left)) #左の塗り方をリストに格納
  rightlist.append("".join(blue_right + "|" + red_right)) #右について同様
left=Counter(leftlist)
right=Counter(rightlist)
 
answer=0
 
for key,value in left.items():
  answer+= value * right[key] #同じkey(分け方)に対するredとblueの通りを掛け合わせる
print(answer)

私も理解が不十分なのですが、分からないところがあればコメントして下さい!(一緒に考えます)

【AGC 026】B. rng_10s

問題文


コンビニエンスストアのりんごマートでは,りんごジュースを販売しています。

りんごマートはある日の朝に開店し,その時にはジュースの在庫が A本ありました。

すぬけ君は毎日昼にりんごマートでジュースを B本買います。

りんごマートでは毎日夜にジュースの在庫を確認し,C本以下だった場合,

次の日の朝までに D本在庫を追加します。

すぬけ君がジュースを永遠に買い続けられるかを判定して下さい。

つまり,ジュースを買おうとした時,必ず在庫が B本以上あるかどうかを判定して下さい。

すぬけ君以外がジュースを買うことはありません。

また,今回の問題では入力ケースは T個のクエリからなります。

制約


  • 1≤T≤300
  • 1≤A,B,C,D≤1018

考え方


  • 買えない場合

初期個数AよりBが多い場合(例.29個しかないのに30個買う)

DよりBが多い場合(夜に10個しか仕入れないのに昼に15個買うと、毎日在庫が減って底を尽きる!)

考えなければならないのが、購入した後のBの在庫数。

これがCより大きければ、買えません

例.

A=13,B=7,C=5の時、

在庫の個数が13個で、7個買ったら6個になり夜に補充もされないので買えない。

B個減らしてD個増やして..を繰り返し反復しているのでは長くて計算が間に合わないので、 何か対策を考える必要があります。 →分からないので解説を読みました。

f:id:inaba00032:20180715201008p:plain https://img.atcoder.jp/agc026/editorial.pdf

.....分からん!

考えたことをソースコードに長々とコメントアウトしてあります。

ソースコード



def gcd(a,b):
  while b:
    a,b=b,a%b
  return a
T=int(input())
 
Query=[]
for i in range(T):
  Query.append(list(map(int,input().split())))
 
for i in range(T):
  while(True):
    if Query[i][0]%Query[i][1]>Query[i][2] or Query[i][0]<Query[i][1] or Query[i][1]>Query[i][3]:
      print('No')
      break;
    G=gcd(Query[i][1],Query[i][3]) #この倍数分の増減のみ考えれば良い
    '''
    A,B,C,DがQuery[i]の0,1,2,3に対応
    BmodG,DmodGは0(GはB,Dの約数であるため)よりmodGの世界で個数の増減はない。昼の購入で0個減少。夜の仕入れで0個増加。
    つまり、初期個数をAmodGとすると、個数は一定
    Bは買う個数であり、B-Gを考えると、買いきれない個数で出現しうる最大の個数が求まる。
    (G分の増減しかないため、B-Gが最大)
    但し、初期個数を考える必要がある。
    初期個数によってループする幅が一緒でも取りうる値は異なる。
    
    例:
    B=24,C=19,D=36 この時,G=12
    本来の個数を見るとGの倍数のみ増減することが分かります。

    A=31の場合 AmodG(本来の個数) 
    7(31)→7(7)→7(43)→7(19)→7(31)→...
    A=30の場合 AmodG(本来の個数)
    6(30)→6(6)→6(42)→6(18)→6(30)→...
    
    Bを超えない最大数について、初期個数を考慮すると、B-G+AmodGとなる。
    G>AmodGであるため、この数が購入数Bを超えることはない
    つまり、B-G+AmodG>CならばNo,そうでなければYes
    '''
    if Query[i][1]-G+Query[i][0]%G>Query[i][2]:
      print('No')
      break;
    else:
      print('Yes')
      break;

私も理解が不十分なのですが、分からないところがあればコメントして下さい!(一緒に考えます)

【ARC 093】D. Grid Components

問題文

2 つの整数 A,B が与えられます。

各マスが白または黒に塗られたグリッドであって以下の条件を満たすものを、出力の項で指定されたフォーマットに従って一つ出力してください。

  • グリッドの大きさを縦 h 行横 w 列としたとき、h および w はともに 100 以下である。
  • 白く塗られたマスの集合はちょうど A 個の連結成分に分かれている (連結成分という単語の定義については後の注釈を参照)。
  • 黒く塗られたマスの集合はちょうど B 個の連結成分に分かれている。

制約の項で指定される条件のもとで解は必ず一つ以上存在することが証明できます。 解が複数ある場合、どれを出力しても構いません。

注釈

2 つの白く塗られたマス c1,c2が連結であるとは、マス c1 からマス c2 へ、上下左右に隣り合うマスへの移動を繰り返して、 白く塗られたマスだけを通って移動できることを意味します。

白く塗られたマスの集合 S が連結成分であるとは、S が以下の条件を満たすことを意味します。

  • S のどの 2 つのマスも連結である。
  • S に含まれないどの白く塗られたマスと、S に含まれるどのマスも連結ではない。
  • 黒く塗られたマスについても連結成分を同様に定義します。

制約

  • 1≤A≤500
  • 1≤B≤500

考え方

下の図のように白と黒の要素で二分された領域を考えて、そこから八方が塞がれたような領域のところだけ違う色(文字)で塗る

f:id:inaba00032:20180617010203j:plain

ソースコードでは1行99文字(1行に50まで違う色を確保できる)にしているけれど、何行でも良いはずです。 色を置き換える数については、上の図でそれぞれ1つずつの連結領域があるため、A-1個(B-1個)置き換える必要があります。

ソースコード


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

#文字を置き換える必要のある'#','.'それぞれのラインの数
a_line=(A-1)//50+1
b_line=(B-1)//50+1
 

#置き換えたものを連結にしないために1ラインごとに1行一つの色を塗る必要がある
print(2*a_line+2*b_line,99)



for i in range(a_line):
 #最後にこの行で50の倍数でない余りの数を塗る
 if i == a_line-1:
  print(('.#'*((A-1)%50)+'#'*(99-2*((A-1)%50))))
 #51以上の場合50個ずつ塗って次の行へ
 else:
  print(('.#'*49)+'.')
 print('#'*99)
 
#上記と同じ
for i in range(b_line):
 print('.'*99)
 if i == b_line-1:
  print(('#.'*((B-1)%50)+'.'*(99-2*((B-1)%50))))
 else:
  print(('#.'*49)+'#')