ABC095(バーチャル):水色競プロerの復習
何だか最近このブログを読んでいただける方が増えてきました。
それも16時~20時の間が多いようです。
サークルか何かでしょうか?
ありがたいような恥ずかしいような感じですが、「この部分をもう少し詳しく」や「その考察に至った過程は?」などリクエストをいただければ極力お答えしたいと思います。
〇コンテスト名:ABC095
〇配点:不明
〇制限時間100分(A~Dまでの4問の時代のコンテスト)
〇今回の方針
本番のコンテストのつもりで解く
前回のABC096に引き続きノーミスを狙います。
コンテスト開始!
A - Something on It
ラーメン1杯700円
トッピングは3種あり、全て1つ100円
トッピングは〇、Xでする、しないが与えられるのでラーメンの価格を求めよ。
〇〇XやX〇Xの形で与えられるトッピング情報をきちんと読み取れるか?
という問題ですね。
countを使う等、方法はいくつかあるのでしょうが、
きっと一番単純なのは下の様に〇の数を数える方法でしょう。
S=input() T=0 for i in range(3): if S[i]=="o": T+=1 print(700+T*100)
1:38 AC
B - Bitter Alchemy
お菓子の素がXあり、N種のドーナツ(お菓子の素使用量はそれぞれmi)を作る。
全種類つくりつつたくさん作りたい。
最大いくつ作れるか求めよ。
まず全ての種類のドーナツを作り、後はお菓子の素の使用量の一番少ないドーナツを作れるだけ作れば良いですね。
問題はどうやってコードに落とし込むかですが、
listとsortとsumを使いましょう。
mはlistで受けて、listをsortすればmの一番小さいものは一番前へ、またlistに対してsumを使えば、listの中身の合計が求められます。
と文章で書いてもわかりにくいので、
コードをどうぞ。
N,X=map(int,input().split()) L=[] for i in range(N): m=int(input()) L.append(m) L.sort() X-=sum(L) print(N+X//L[0])
4:00 AC
C - Half and Half
AピザBピザと、Aピザ0.5枚とBピザ0.5枚分に相当するCピザがそれぞれA,B,C円である。
AピザとBピザをそれぞれX,Y枚ずつ欲しい。
必要な最低金額を求めよ。(ピザにあまりが出ても良い)
Cピザを買う枚数が決まればAピザ、Bピザの必要枚数が決まります。
また、Cピザは必ず偶数枚(ゼロを含む)購入するので、
まずはansにありえない大きさの数字を入れておいて、
Cピザの枚数毎の合計金額を求め、それまでの最低金額が出たら更新します。
A,B,C,X,Y=map(int,input().split()) ans=10**10 for i in range(max(X,Y)+1): cnt=0 cnt+=C*2*i x=X-i y=Y-i cnt+=max(0,x*A) cnt+=max(0,y*B) if ans>cnt: ans=cnt print(ans)
8:17 AC
D - Static Sushi
円形状のテーブルに寿司があり、時計回りに動いた際の距離xとカロリーvが与えられる。
好きな向きに動き、好きな位置で退店して良いが、距離1を移動する毎に1カロリー消費する。
得られる最大カロリーを求めよ。
これは難しいですね。
過去に開設を読んで解いた問題ですので考え方は知っているのですが、それでも実装に時間がかかりました。
時計周りに進み、各寿司を食べた時点での(カロリーの合計ー移動距離)から開始地点に戻るための移動距離を引き、
反時計回りに各寿司を食べ進んで得られるカロリーを求める。
累積和を使い、時計回りに進んだ後、反時計回りに進んで得られる最大のカロリーの計算を高速化する。
同様に反時計周りから始める場合も計算する。
import sys import copy input=sys.stdin.readline N,C=map(int,input().split()) Arr=[] for i in range(N): x,v=map(int,input().split()) Arr.append([x,v]) Rev=copy.deepcopy(Arr) Arr=[[0,0]]+Arr Dis=[] for i in range(len(Arr)): Dis.append(Arr[i][0]) #print(Arr) Rev=Rev[::-1] for i in range(N): Rev[i][0]=C-Rev[i][0] Rev=[[0,0]]+Rev #print(Rev) RevDis=[] for i in range(len(Rev)): RevDis.append(Rev[i][0]) #print(RevDis) ArrV=[0] S=0 for i in range(1,N+1): S+=Arr[i][1] ArrV.append(S-Dis[i]) #print(ArrV) ArrVR=[0] for i in range(1,N+1): ArrVR.append(max(ArrVR[-1],ArrV[i])) #print(ArrVR) RevV=[0] S=0 for i in range(1,N+1): S+=Rev[i][1] RevV.append(S- RevDis[i]) #print(RevV) RevVR=[0] for i in range(1,N+1): RevVR.append(max(RevVR[-1],RevV[i])) #print(RevVR) ans=0 for i in range(N+1): cnt=ArrVR[i]-Dis[i]+RevVR[N-i] ans=max(ans,cnt) for i in range(N+1): cnt=RevVR[i]- RevDis[i]+ArrVR[N-i] ans=max(ans,cnt) print(ans)
46:23 AC
46:23で全完(4完)0ペナ
Dは初見では厳しいですね。
ABC096(バーチャル):水色競プロerの復習
前回のABC155でD,Eが解けず、3回連続でレートが下がってます。
もう少し時間があればDは解けたのに・・
後半の問題を解くための時間を確保するためには、前半を早解きするしかないですね。
と言うわけで、今日も過去のABCの復習で精進しました。
〇コンテスト名:ABC096
〇配点:不明
〇制限時間100分(A~Dまでの4問の時代のコンテスト)
〇今回の方針
本番のコンテストのつもりで解く
ABC097はミスが多く4ペナだったので、今回はノーミスを狙います。
コンテスト開始!
A - Day of Takahashi
2018年1月1日~2018年a月b日までの間に、月と日の数字が同じになる日が何回あるか求めよ。
1月1日、2月2日、3月3日・・a<=b ならa回、そうでなければa-1回ですね。
a,b=map(int,input().split()) if a<=b: print(a) else: print(a-1)
2:07 AC
B - Maximum Sum
1以上の整数A,B,Cが与えられる。任意の数字を2倍する操作をK回行った後のA+B+Cの最大値を求めよ。
1番大きい数字を2倍し続けるのが最善でしょう。
どうやって1番大きい数字を探すかですが、ifをたくさん書いても良いのですが、
A,B,Cをリストに入れておいて、ソートするのが簡単だと思います。
入力の段階からA,B,Cではなく、listで受けました。
List=list(map(int,input().split())) List.sort() K=int(input()) for i in range(K): List[2]*=2 print(sum(List))
4:40 AC
キャンパスが"."と"#"で埋められている。"#"は全て上下左右のいずれかに"#"が隣接していればYes、そうでなければNoを出力せよ。
キャンパス上を全探索して、"#"であった場合は上下左右のいずれかに"#"があることを確認。
この手の問題は、キャンパスの外周を"."で囲ってしまえば、渕の部分での境界を気にしなくて良いですね。
また、X=[1,-1,0,0] Y=[0,0,1,-1]とし、for i in range(4);で上下左右を確認するのもお約束ですね。
H,W=map(int,input().split()) L=[] l=["." for i in range(W+2)] L.append(l) for i in range(H): S=["."]+list(input())+["."] L.append(S) L.append(l) X=[1,-1,0,0] Y=[0,0,1,-1] for h in range(1,H+1): for w in range(1,W+1): if L[h][w]=="#": F=0 for i in range(4): if L[h+X[i]][w+Y[i]]=="#": F=1 if F==0: print("No") exit() print("Yes")
11:02 AC
D - Five, Five Everywhere
5~55の整数Nが与えられる。
異なる素数N個を並べ、どの5つを選んでも合成数となる数列を作成せよ。
まずは素数を並べろというので、素数を集めましょう。
素数といえばエラトステネスの篩。
①中身が全て1のリストを作成
②リストの0番と1番を0にする
③リストを順に見ていき、for i in range((2,N): list[i]が1であればfor j in range(2,N):でループを回し、list[i][j]を0にする。
④リストの1になっている部分が素数。
そして、どの5個を選んでも合計が合成数になる組み合わせ。
下1桁が1の素数をN子集めれば良いですね。
(解いた後で気づきましたが、下1桁が1である必要はなく、下1桁がそろってさえいれば5個の合計の1の位は5になるわけで、必ず合成数になりますね。
それに気づけばあとは書くだけ。
P=[1 for i in range(55556)] P[0]=0 P[1]=0 for i in range(2,55556): if P[i]==1: for j in range(2,55556): if i*j<=55555: P[i*j]=0 else: break ans=[] for i in range(55556): if P[i]==1 and i%10==1: ans.append(i) N=int(input()) print(*ans[:N])
19:14 AC
結局 19:14で全完(4完)0ペナでした。
当時は約90分で4ペナながらも全完してパフォ1200オーバー!
ちなみに、当時のレートは・・ゼロ!
なんとこのコンテストが私のはじめてのコンテストでした。
いや、今でもレートは1300ちょっとしかないんですけど・・
ほとんど成長していない?
ABC097(バーチャル):水色競プロerの復習
昨日はお休みして、今日はABC097でバーチャルコンテスト。
朝にバチャやってる方々もおられるようですが、出勤時間的に出られないんです。出られる方羨ましい・・
なので夜に一人でやってます。
〇コンテスト名:ABC097
〇配点:不明
〇制限時間100分(A~Dまでの4問の時代のコンテスト)
〇今回の方針
本番のコンテストのつもりで解く
とにかく速く解く
コンテスト開始!
位置a,b,cに人がいる。人同士は距離d以内であれば通信できる。aとcは通信できるか?
勝手に位置関係をa,b,cの順にしてしまいたくなりますね。
テストケースが親切なので気づきますけど。
aとcがd以内、もしくはaとb,bとcがd以内ならOKですね。
a,b,c,d=map(int,input().split()) if abs(a-b)<=d and abs(c-b)<=d: print("Yes") elif abs(a-c)<=d: print("Yes") else: print("No")
2:21 AC
Xが与えられ、X以下の最大のべき乗数を求めよ。
はい簡単
ループを回してiを増やしていきながら、i**2=Xならi**2を出力i**2>Xなら(i-1)**2を出力すれば、
WA
ちゃんと問題文を読みましょう。
2乗とは限らないんですね。
ただ、Xが1000以下。そして2**10=1024を知っていれば、10乗以上を考える必要がないことがわかります。
Xが1のときは考えるのが面倒なので、例外処理で1を出力してしまいます。
あとは変数ansを用意しておいて、iとjの2重ループを回す。j**iがX以下でansより大きければans=j**i。
X=int(input()) if X==1: print(1) exit() ans=1 for i in range(2,11): for j in range(1001): if j**i<=X: if ans<j**i: ans=j**i print(ans)
8:21 AC 1WA
なにやってんの?
あと、計算量的に余裕なのでやりませんでしたが、10**6オーダーの計算量ならj**iがXを超えた時点でbreakして枝刈りすべきでしょうね。
sの部分文字列に関する問題で辞書順でK番目になる連続する部分文字列(同じ文字列は1つとして数える)を求めよ。
一か八か全探索。dictを用意して、初めと終わりを2重ループさせて全探索。dict内に同じ文字列が無ければ加える。
最後にdictをlistに変換してソート、listのK番目を出力!
TLE
やっぱ無理です。これで通るならB問題より簡単です。
良く見ればKが1~5ととても小さい。
これならlist Lを用意して、部分文字列の初めと終わりを2重ループさせて全探索。
面倒なのでLには空文字””を入れておく。
・部分文字列がLに含まれていないことを確認。
・Lの長さがK以下ならLに部分文字列を加えてソート
・Lの長さがK+1なら、Lの最後と部分文字列の辞書順を比較。
・部分文字列の方が前にくるなら、部分文字列をLに加えて、ソート。
Lの一番後ろを切る。
・部分文字列の方が後にくるならループをbreakして枝刈り。
最後にLの一番後ろを出力
S=input() K=int(input()) L=[""] for s in range(len(S)): for e in range(s,len(S)): if S[s:e+1] in L: continue if len(L)>K: if S[s:e+1]>L[K]: break if S[s:e+1] not in L: if len(L)<=K: L.append(S[s:e+1]) L.sort() else: L.append(S[s:e+1]) L.sort() L=L[:K+1] print(L[-1])
31:27AC 1TLE 2WA
14行目のソートを忘れててテストケースに1つだけ通らず2WA
結局C問題だけで3ペナ。B問題と合わせて4ペナ。
1からNを並べ替えた数列pがある。1~N以下の整数ペアがM個与えられ、ペアの数字は何回でも入れ替えて良い。
左からの順番と整数が一致する箇所を最大いくつにできるか?
unionfindとdictを組み合わせれば良さそうですね。
左からi番目を見ているときは、i番目と整数iの位置が同じグループか否かを判断。
N,M=map(int,input().split()) p=[0]+list(map(int,input().split())) P=[i for i in range(N+1)] S=[1 for i in range(N+1)] def find(a): if a==P[a]: return a else: return find(P[a]) def union(b,c): B=find(b) C=find(c) if S[B]<S[C]: P[B]=P[C] S[C]+=S[B] else: P[C]=P[B] S[B]+=S[C] for i in range(M): x,y=map(int,input().split()) union(x,y) D={} for i in range(1,N+1): D[p[i]]=i ans=0 for i in range(1,N+1): if find(i)==find(D[i]): ans+=1 print(ans)
43:52 AC
結局 43:52全完(4完)4ペナ!!!!
緊張感が足りてませんね。
ABC098(バーチャル):水色競プロerの復習
一昨日のABC100、昨日のABC099に続き、今日はABC098でバーチャルコンテストしました。
コンテストの時期的に、これもリアルタイムで参加したはずです。
〇コンテスト名:ABC098
〇配点:不明
〇制限時間100分(A~Dまでの4問の時代のコンテスト)
〇今回の方針
本番のコンテストのつもりで解く
とにかく速く解く
コンテスト開始!
A - Add Sub Mul
何も考えず、A+B,A-B,A*Bの最大値を出せば良いですね。
A,B=map(int,input().split()) print(max(A+B,A-B,A*B))
1:00 AC
B - Cut and Count
英小文字からなる文字列が与えられる。どこかで切って、前半にも後半にもある文字の種類数の最大値を出力せよ。
文字で説明は難しいですね。
リストの中に0が26個並んだリストを用意して、aが出たら最後のリストの0番目を+1して加える、cが出たら2番目を+1して加える・・
やっぱりコードを見ていただく方が良さそうです。
N=int(input()) S=list(input()) import copy A=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"] L=[[0 for i in range(26)]] for i in range(N): l=copy.deepcopy(L[-1]) for j in range(26): if S[i]==A[j]: l[j]+=1 L.append(l) ans=0 for i in range(N): cnt=0 for j in range(26): if L[i][j]>0 and L[-1][j]-L[i][j]>0: cnt+=1 if ans<cnt: ans=cnt print(ans)
9:13 AC これB問題とは思えない難易度なんですが。想定解ではなかったのでしょうか?
C - Attention
人が1列に並んでいる。人は東もしくは西を向いている。リーダーを適切に選んだ時、全員をリーダーの方に向かせ(リーダーはどちらを向いていても良い)るのに向きを変える最小の人数を求めよ。
西から順に西を向いている人数の累積和を求める。
同様に東から順に東を向いている人数の累積和を求める。
リーダーの位置を全探索。
で求められますね。
これBより簡単なのでは?
N=int(input()) S=list(input()) RS=S[::-1] W=[0] E=[0] for i in range(N): if S[i]=="W": W.append(W[-1]+1) else: W.append(W[-1]) W.append(0) for i in range(N): if RS[i]=="E": E.append(E[-1]+1) else: E.append(E[-1]) E.append(0) E=E[::-1] #print(W) #print(E) ans=10**9 for i in range(1,N+1): if W[i-1]+E[i+1]<ans: ans=W[i-1]+E[i+1] print(ans)
はいフラグ回収!
22行目のN+1が最初Nになっていて1WA
WAの原因を探るためにプリントデバッグして、そのまま19,20行目のコメントアウトを忘れてもう1WA
23:28 2WA
D - Xor Sum 2
連続する区間の合計=区間の全てのXORとなる範囲の数を求めよ。
合計を持って置き、先頭の先を足したもの=先頭の先のXORであれば先頭を伸ばし、合計も増やす。そうでなければ、それまでの先頭と終わりの差を答えに足す。を繰り返す。
これも文章では難しいですが、やっていることは難しくないです。
N=int(input()) A=[0]+list(map(int,input().split()))+[0] x=[0] for i in range(1,2*(10**5+3)): x.append(x[-1]+i) S=0 E=0 SUM=0 ans=0 for i in range(10**6): if S==N+1: ans+=x[(S-E-1)] break if SUM+A[S+1]==SUM^A[S+1]: SUM+=A[S+1] S+=1 else: ans+=(S-E) SUM-=A[E+1] E+=1 #print(ans,S,E,SUM) print(ans)
68:02 AC
難しいことをしていないのにバグがとれず、時間がかかってしまいました。
実装力の無さを実感しています。
結局68:02 全完(4完) 2WA
過去のABCによる精進は水色下位には有効そうですね。
ABC099(バーチャル):水色競プロerの復習
昨日のABC100バーチャルコンテストは、緊張感が出てとても良い精進になったので、今日もABC099で復習しました。
コンテストの時期的に、これもリアルタイムで参加したはずです。
〇コンテスト名:ABC099
〇配点:不明
〇制限時間100分(A~Dまでの4問の時代のコンテスト)
〇今回の方針
本番のコンテストのつもりで解く
緊張感を大切に
コンテスト開始!
A - ABD
与えられたNが999以下ならABCと、1000以上ならABDと出力。
ただそれだけの問題なのに、勝手にNが90ならABC090と、数字部分はゼロ埋めしようとしました。
地味に1分弱のロス。これを本番でやると、時間のロスは大したことなくても焦りますね・・
問題文とテストケースの解答は良く見ましょう。
それさえできれば難しくない問題
N=int(input()) if N<=999: print("ABC") else: print("ABD")
1:49 AC
B - Stone Monument
地味にこれB問題としては難しくないですか?
問題文の式を見れば、bが西から何番目かはb-aで求まることがわかります。
bが西から何番目かがわかれば、bの高さ(雪に埋もれてない場合)は1+2+・・+(b-a)で求まります。
bの高さ(雪に埋もれてない場合)-b(雪の上に出ている高さ)を出力すれば良いですね。
a,b=map(int,input().split()) N=b-a H=0 for i in range(N+1): H+=i print(H-b)
4:17 AC
C - Strange Bank
はいこの良問見て思い出しました。
この回のコンテストには参加してます。
コンテスト当時はこれができず、1時間以上固まってました。
今ならどうするか。
まず、1回の引き出しでおろせる額のリストを作ります。
6**1,6**2・・10**5を超えない範囲で加えていく。
同様に9**1,9**2・・10**5を超えない範囲で加えていく。
次に、DP用リストを用意し、dp=[i for i in range(N+1)]
これは全てを1円玉で払った枚数。
これに対し、上で作ったリストを使い
dp[i]=min(dp[i],dp[i-1回で引きおろせる額]+1)として更新
文章ではわかりにくいのでコードをどうぞ
Coin=[] for i in range(1,100): if 6**i<=10**5: Coin.append(6**i) for i in range(1,100): if 9**i<=10**5: Coin.append(9**i) N=int(input()) dp=[i for i in range(N+1)] for c in Coin: for i in range(N+1): if i-c>=0: dp[i]=min(dp[i],dp[i-c]+1) print(dp[N])
9:15 AC
D - Good Grid
全探索
まずは、色は30色までしかない。そして、3で割ったあまりは0,1,2の3通りしかない。
そこで、あまり0~2の3種に対し、長さ30のリストを作る。
各あまり毎に色Cがいくつあるかを集計しておく。
あまり0~2をどの色にするか全探索。
itertoolsをインポートして、itertools.permutationsを使うと楽に全部の色の組み合わせを作成できますね。
そして、あまり0~2をどの組み合わせにすれば違和感が少ないかを全探索
ところが、コードの最後でansを出力していますが、ここを誤ってcntとしていて、答えが合わずに困りました。
コンテスト本番でなくて良かった。
N,C=map(int,input().split()) D=[] D.append([0 for i in range(C+1)]) for i in range(C): d=[0]+list(map(int,input().split())) D.append(d) L=[] for i in range(N): c=list(map(int,input().split())) L.append(c) M0=[0 for i in range(C+1)] M1=[0 for i in range(C+1)] M2=[0 for i in range(C+1)] for i in range(N): for j in range(N): if (i+j)%3==0: M0[L[i][j]]+=1 elif (i+j)%3==1: M1[L[i][j]]+=1 elif (i+j)%3==2: M2[L[i][j]]+=1 Col=[i for i in range(1,C+1)] import itertools Arr=list(itertools.permutations(Col,3)) ans=10**20 for i in range(len(Arr)): cnt=0 for j in range(1,C+1): cnt+=M0[j]*D[j][Arr[i][0]] cnt+=M1[j]*D[j][Arr[i][1]] cnt+=M2[j]*D[j][Arr[i][2]] if ans>cnt: ans=cnt print(ans)
34:03 AC
結局34:03ノーペナで全完!
コンテスト当時は2完だったので、成長しているようです。
ABC100(バーチャル):水色競プロerの復習
今日は休日ですが、AtCoderのコンテストはありません。
こんな日は過去問の復習をしましょう。
過去に苦戦した問題を解くのも良いですが、コンテスト気分を味わいたくてバーチャルコンテストにしました。
問題は何も考えずにABC100に決定(この時点では参加したか否かの確認も無し。特別な用事がなければ参加しているはずですが。)。
〇コンテスト名:ABC100
〇配点:不明
〇制限時間100分(A~Dまでの4問の時代のコンテスト)
〇今回の方針
本番のコンテストのつもりで解く
考察は早く、でもWA気にせず適当にぶん投げるのは無し
コンテスト開始!
A - Happy Birthday!
丸いケーキを16等分した。A,Bの2人で分けるが隣り合うケーキは同じ人が取ってはならない。A,Bどちらも欲しいだけケーキをとれるか?
テストケースに絵が描いてあって親切ですね。
A,Bともに8切れまでしかとれないことがわかります。
A,Bともに8以下ならYay!、そうでなければ:(を出力。
E869120 さんとsquare1001さんの双子の問題は出力が変わっていることが多いですね。Yay!はまだ良いとしても、:(はコピペで持ってこないと危険ですね。これの入力ミスでWAを食らったら目も当てられません。
A,B=map(int,input().split()) if A<=8 and B<=8: print("Yay!") else: print(":(")
1:42 AC
B - Ringo's Favorite Numbers
100でちょうどD回割り切れるN番目の数を出力せよ。
何言ってるかわかりにくい問題文ですが、テストケースを見ればわかりますね。
制約を見れば、Dは0,1,2でNは100まで。
基本的にNに100のD乗をかければ良いですが、Nが100の時だけ注意!
Dが1でNが100の場合、10000を出力するとWA。10000は100で二回割り切れますからね。
制約条件から、100の時だけ別処理(Nを101にしてしまえば良いでしょう)
D,N=map(int,input().split()) if N==100: N=101 print(N*100**(D))
5:28 AC
C - *3 or /2
問題文見た瞬間「はいコラッツ!」
違いました。
問題文を読んでテストケースを見て、問題が「2で何回割れるか?」であることを理解するまでの時間の勝負。
3をかける意味はありません。
このへんは慣れでしょうか。
問題文が「2で何回割れるか?」になれば難しくはないはず。
N=int(input()) A=list(map(int,input().split())) ans=0 for i in range(N): while A[i]%2==0: A[i]//=2 ans+=1 print(ans)
7:59 AC
D - Patisserie ABC
M個のケーキのxの和の絶対値+yの和の絶対値+zの和の絶対値の最大値はいくつか?
絶対値と言うことは、マイナスの場合も考慮しないといけませんね。
きれいさ、おいしさがマイナスのケーキってどんなケーキだよ?と言うのはここでは考えません。
3種類(x、y、z)の正と負で2**3=8個のリストを用意して、
x,y,z全てが正のリストはLPPP
xが正でy,zが負のリストはLPMM
(Lはリストの頭文字、Pはプラス、Mはマイナスのイメージで付けました)
みたいな感じで各リストの上位M個を比べて一番大きいものを出力!
文字で説明よりコードを見た方が速いでしょう。
N,M=map(int,input().split()) LPPP=[] LPPM=[] LPMP=[] LPMM=[] LMPP=[] LMPM=[] LMMP=[] LMMM=[] for i in range(N): x,y,z=map(int,input().split()) LPPP.append(x+y+z) LPPM.append(x+y-z) LPMP.append(x-y+z) LPMM.append(x-y-z) LMPP.append(-x+y+z) LMPM.append(-x+y-z) LMMP.append(-x-y+z) LMMM.append(-x-y-z) LPPP.sort(reverse=True) LPPM.sort(reverse=True) LPMP.sort(reverse=True) LPMM.sort(reverse=True) LMPP.sort(reverse=True) LMPM.sort(reverse=True) LMMP.sort(reverse=True) LMMM.sort(reverse=True) print(max(sum(LPPP[:M]),sum(LPPM[:M]),sum(LPMP[:M]),sum(LPMM[:M]),sum(LMPP[:M]),sum(LMPM[:M]),sum(LMMP[:M]),sum(LMMM[:M])))
19:15 AC
全て解いたことのある問題だったので、何なく解けました。
と言うか、このコンテストにはリアルタイムで参加して全完していますね!
しかも当時(約1年8カ月前)の私のレートは646でこの回のパフォ1480!!
今のレートは1300ちょっとなので、今でもパフォ1480はなかなか出ません。まるで成長していない・・
水色競プロerの妄想(RPAに必要なプログラミングスキル)
妄想の前にsyunsukeのプロフィール
・AtCoderレート1300強(2020年1月末時点)の水色コーダー
・40代の子持ちサラリーマンでプログラマーではありません。
(プログラマーとしての経験もなく、コードを書いて収入を得たこともありません)
・勤務時間はデスクワーク半分、(ラボで手を動かす+営業活動)でもう半分くらいの配分です。
・最近RPAが気になるお年頃
以上の前提で読んでいただければ幸いです。
少し前からRPAがえらく流行っているようですので、私も触ってみました。
流行りもののRPAに手を出してみたのですが、RPAツールはスクラッチの様に直感的な操作で簡単に動くものが作れますね。ExcelのVBAで自動化ツールを作ったことはありますが、他の人にはメンテ不能なものになってしまい、結局私専用ツールとなった過去を持つものとしては感涙ものです。これなら他の人でもメンテできそうです。さすが流行っているだけのことはあります。
これは爆発的に広まるに違いない!世界が大きく変わる!
と思ったのですが、そうでもないようです。
私が感動したRPAツールですが、周囲の評判は良くありません。聞くと、ループの中にループが入ると混乱するそうです。
よくあるRPAの使い道で、「Excelのセルに入力された内容をWebアプリに転記する」と言うものがありますが、これはループを回さないといけません。1行目・・H行目までループを回して1重ループ。さらにそれが数列に渡っていれば2重ループ。加えてExcelブックが複数あればその数だけ回して3重ループ。
これでわからなくなってしまうそうです。
確かに、競プロを始めた頃は、縦横の2重ループを回していると混乱していた気がします。
さすがに、他重ループを使わなかったらRPAもあまり良いものではなさそうです。
残念ですが、RPAは断念しましょう・・
なわけないでしょう。
勉強しましょう。
2世代前はメールでやりとりしてWordで文書を書いてExcelで計算できるスキルを持つ人は少なかったはずですが、だんだん増えて、今はできて当然。ここに簡単なプログラミングスキルが加わり、これからだんだん増えるのではないでしょうか。また、ここで言うプログラミングスキルとは
・if文で条件分岐させる
・for かwhileのどちらかでループを回す
・2,3重ループを感覚的に理解する
・intとstrの型を理解する
・リスト(2次元まで)を扱えるようになる
をイメージしています。
1年前のAtCoderなら茶色(レート400以上)くらいでしょうか、今はこのあたりのレベルが上がりすぎて良くわかりませんが。
プログラマーでない人にこのレベルのスキルがあれば、RPAは便利なツールになるでしょう。今であれば、30人くらいまでの組織に1人確保し、有効に活用できれば重宝するのではないでしょうか。
また、文字列操作やその他ある程度複雑な処理も期待できる緑(レート800以上)相当であれば、200人を超える大きさの組織なら、1人置いておきたいところですね。
そこで、どうやって簡単なプログラミングスキルを持つ人材を育成するかと言えば、やっぱり競プロでしょう。で、何をするかと言えば、AtCoderやyukicoder等にアクセスさせるだけ。適性のある人は勝手に力を付けていくでしょう。その中から何人かは茶色コーダーになり、さらにその中の何人かは緑コーダーになり、そんな人が増えれば、世の中の様子も変わっていく気がします。
以上水色競プロerの妄想でした。