きなこの精進日記[python]

エイシング プログラミング コンテスト 2020 A~D解説

しょうもない実装ミス、誤読を直せずA,Bの2完でした(え?)

A - Number of Multiples

概要

L 以上 R以下の整数のうち、dの倍数であるようなものはいくつありますか?

考察

基本的にはl,r をd で割った商の差を取れば良い。ただし、l がd で割り切れる時は、+1する

#!/usr/bin/env python3
l, r, d = map(int, input().split())
print(r // d - l // d + (l % d == 0))

B - An Odd Problem

概要

1,..N の番号が書かれたマスがあり、それぞれ値A[i] を持つ。
Nこのマスのうち、番号、値が共に奇数であるマスの数を求めよ

考察

1つずつマスを見てO(N)
スライスを使うと奇数ますだけ見れて楽

#!/usr/bin/env python3
n = int(input())
a = list(map(int, input().split()))
ans = 0
for i in range(0, n, 2):
    if a[i] % 2:
        ans += 1

print(ans)

C - XYZ Triplets

概要

1<=a,b,c
a ** 2 + b ** 2 + c ** 2 + a * b + b * c + c * a = n
を満たすa,b,c の組み合わせを1<=n<=N に対してそれぞれ求めよ

制約

N<=10**4

考察

1<=a,b,c より、a ** 2 + b ** 2 + c ** 2 + a * b + b * c + c * a はa**2 ,b**2,c**2よりは大きくなるから、条件を満たすa,b,c, は100未満である。

つまり1~99までa,b,cを全探索すれば良い。

ただし、n をループさせるとO(N)*100**3となってTLEするので、それぞれのn に対して個数を持つリストを用意して、a,b,cの全探索での値がN以下ならそこに対応する個数を+1すれば良い

#!/usr/bin/env python3
n = int(input())
cnt = [0] * (1 + n)
for a in range(1, 100):
    for b in range(1, 100):
        for c in range(1, 100):
            k = a ** 2 + b ** 2 + c ** 2 + a * b + b * c + c * a
            if k > n:
                continue
            else:
                cnt[k] += 1
for i in range(1, n + 1):
    print(cnt[i])

D - Anything Goes to Zero

概要

D - Anything Goes to Zero
説明しにくいのでリンク
2進数をそれに含まれる1の個数で割っていったあまりに更新するという操作を繰り返す

制約

1<~N<=2*10**5

考察

 桁数が2*10**5なので、まともに計算するとオーバーフローするし、時間がかかる。
 オーバーフロー対策として、mod だけ取れば良いのでmod で計算する。
ただ、1回操作を行うと、1の個数以下になるので2*10**5以下になり大幅に減る。

 それぞれの反転で1の数は+1 or -1 になるので、初期の1の値をcntとすると、cnt+1とcnt-1をmodにした時の値をそれぞれもち、それぞれのbit反転数に対してbit反転した後の値をそこから計算した後、それ以降の操作を行えば良い。

 操作をstepごとにまとめると以下のようになる
step1; 1を数える cnt_1
step2 : 全体の計算をする cnt1 + 1 とcnt1 -1 それぞれ
step3 : それぞれの桁に対して0 なら cnt+ 1 を適用 + 2**k mod cnt + 1
1ならcnt - 1 を適用 - 2**k mod (cnt-1)
step4 : その中でf(x)を0になるまで計算

実装

#!/usr/bin/env python3
n = int(input())
x = input()
cnt = x.count("1")
x_cnt_plus = 0
x_cnt_minus = 0
for i in range(n):
    if x[i] == "1":
        x_cnt_plus += pow(2, n - i - 1, cnt + 1)
        x_cnt_plus %= cnt + 1
        if cnt > 1:
            x_cnt_minus += pow(2, n - i - 1, cnt - 1)
            x_cnt_minus %= cnt - 1
for i in range(n):  # 上からi 桁目に注意
    if x[i] == "0":
        f = x_cnt_plus + pow(2, n - i - 1, cnt + 1)
        f %= cnt + 1
    else:
        if cnt == 1:
            print(0)
            continue
        f = x_cnt_minus + cnt - 1 - pow(2, n - i - 1, cnt - 1)
        f %= cnt - 1
    ans = 1
    while f != 0:
        cnt_f_1 = 0
        k = f
        while k:
            if k % 2:
                cnt_f_1 += 1
            k //= 2
        f = f % cnt_f_1
        ans += 1
    print(ans)