AtCoder ABC105: D - Candy Distribution
区間和は「累積和の差分」で考えてみましょう。水色diff です。
問題
数列 の区間
で
が
の倍数であるものの数を求めよ。
制約
考察
の累積和
を計算し、
とします。
求める値は、 の剰余の数列
で、同じ値が何度出てくるかの総和と等しくなります。
Pythonでは collections.Counter が便利です。
values() で出現回数が取得できます。
実装例
N, M = map(int, input().split()) A = list(map(int, input().split())) S = [0] + list(itertools.accumulate(A)) T = [s % M for s in S] counter = collections.Counter(T) ans = sum(n * (n-1) // 2 for n in counter.values()) print(ans)
AtCoder 第六回 アルゴリズム実技検定 (PAST): N - 活動
「条件を手で計算してみる大切さ」を教えてくれる問題です。 ソートしてからナップサックDPで解けます。
問題
種類の活動の中から
つ以上を選び、好きな順序で行なう。
最初の体力は
であり、活動
を行うと、得点
を得た後、体力が
減少する。
得られる得点の和の最大値を求めよ。
制約
考察
活動を行った時に得られる得点が「その時点の体力」に依存するので、そのままナップサックDPは使えません。
しかし、活動の順序を全検索( 通り)することは、時間的に不可能です。
ここで、活動 → 活動
を行った場合と、活動
→ 活動
を行った場合の、それぞれ得られる得点を計算してみます。
体力の減少は、どちらも同じ
です。
得られる得点の差は、
それで、
となります。ゆえに、 が大きい方から処理する(降順でソート)のが最善です。
実装例
INF = 10**10 N, H = map(int, input().split()) Activities = [] for i in range(N): a, b = map(int, input().split()) Activities.append((a, b)) Activities.sort(key=lambda x: (x[0]/x[1]), reverse=True) dp = [[-INF] * (H+1) for _ in range(N+1)] dp[0][H] = 0 for i in range(N): A, B = Activities[i] for h in range(H+1): dp[i+1][h] = max(dp[i+1][h], dp[i][h]) if h > 0: h1 = max(h-B, 0) dp[i+1][h1] = max(dp[i+1][h1], dp[i][h] + A*h) print(max(dp[N]))
DP高速化
ここからは趣味の範囲です。
このコードで、PyPy で 336 ms でACできますが、さらに高速化できます。
は
にしか依存しないので、
を管理するのではなく、
(
dpとする) と (
dp1とする)の2つのみ管理するようにします。
ループごとに dp1 を dp で更新し、ループの最後に dp を dp1 に置き換えます。
dp = [-INF] * (H+1) dp[H] = 0 for A, B in Activities: dp1 = [-INF] * (H+1) for h in range(H+1): dp1[h] = max(dp1[h], dp[h]) if h > 0: h1 = max(h-B, 0) dp1[h1] = max(dp1[h1], dp[h] + A*h) dp = dp1 print(max(dp))
これで、PyPy で 260 ms です。
さらに、配るDPの更新の時に大きい のみを更新しているので、
1本を
で更新していけばOKです。
dp = [-INF] * (H+1) dp[H] = 0 for A, B in Activities: for h in range(H+1): if h > 0: h1 = max(h-B, 0) dp[h1] = max(dp[h1], dp[h] + A*h) print(max(dp))
これで、PyPy で 150 ms です。
ただし、これでもPythonではTLEします。
計算量 が
なので、PyPyでないと時間が厳しいです。
AtCoder ABC208 D - Shortest Path Queries 2
ワーシャル・フロイド法の理解を問う問題です。 緑diffです。
問題
を
頂点
辺の有向グラフ、
を
から
へ頂点番号
以下の頂点のみ経由したときの最小距離とする。
を求めよ。
制約
考察
全点間の距離なので、計算量 のワーシャル・フロイド法が思いつきます。
しかし、
に対してワーシャル・フロイド法を用いると、全体で
になり、間に合いません。
ここで、ワーシャル・フロイド法のコード
for k in range(N): for i in range(N): for j in range(N): if cost[i][k] != INF and cost[k][j] != INF: cost[i][j] = min(cost[i][j], cost[i][k] + cost[k][j])
を眺めると、一番外側の のループがまさに、頂点
を付加して全点間の距離を更新する処理になっていることが分かります。
それで を、
で初期化し、 の順に処理します。
の時の全点間の距離の和は差分処理で求めています。
実装例
INF = 10**15 N, M = map(int, input().split()) cost = [[INF] * N for _ in range(N)] for i in range(N): cost[i][i] = 0 for _ in range(M): a, b, c = map(int, input().split()) cost[a-1][b-1] = c v = 0 for a in range(N): for b in range(N): v += (cost[a][b] if cost[a][b] < INF else 0) ans = 0 for k in range(N): for a in range(N): for b in range(N): d = cost[a][k] + cost[k][b] if d < cost[a][b]: v += -(cost[a][b] if cost[a][b] < INF else 0) + d cost[a][b] = d ans += v print(ans)
商用利用可!海外のフリー写真素材サイトまとめ ― 2020年版

海外のフリー写真素材サイトをまとめました。2020年の決定版です。
このページで紹介されているサイトは全て、ライセンスが
- 商用利用も OK
- 編集・合成等 OK
- 使用時に出典の明記の義務なし
("photo by ~"、みたいな文言や、サイトへのリンク。英語では"attribute"という)
の条件を満たすものだけ選びました。多くのサイトが、美麗な写真を クリエイティブ・コモンズ・ゼロ のライセンスで公開しています。
加えて、
- キーワードで写真を検索できる
という条件もつけました。
無料でプロレベルのクオリティの写真がたくさんありますよ!
続きを読む実戦棋譜001 四間飛車 対 居飛車持久戦

棋力向上のためには、実戦で人と指すだけでなく、実戦を振り返って反省することが欠かせません。
対戦相手と感想戦を行なって、間違った手を指摘してもらったり、変化を一緒に考えたりするのが理想です。しかしネット将棋で感想戦は難しいです。将棋ウォーズでは感想戦を行なうシステム自体ありません。
それで、自分の気力向上のために、実戦棋譜と自分なりの分析をブログに載せて、見ていただこうと思います。
現在の私:
- 現在の実力: 将棋ウォーズ2級
- 棋風・方針: 四間飛車だけ
- 目標: 将棋ウォーズ初段
アマ2級の棋譜ですが、初心者と笑わずに、どうぞ見ていただければと思います。そして感想やアドバイスを、コメントやTwitterで寄せていただければ、大変嬉しいです。
将棋ウォーズ10分切れ負けの棋譜です。ソフトは elmo + やねうら王 を使っています。
続きを読む




