Processing math: 100%

Tenka1 Programmer Contest C,D

C - Align

問題

  • N 個の整数 A1,A2,...,AN を好きな順に並び替える
  • 隣り合う2数の差の合計の最大値を求めよ

1  2  3  4  5
↓
2  5  1  4  3
 \/ \/ \/ \/
 3 +4 +3 +1 = 11

解法

並び替えた後の数列を、偶数番目と奇数番目にわけると、どちらかが中央値以上、どちらかが中央値以下に分けられる。

   5     4
2     1     3

そこで、中央値で区切ってみると、端以外は「中央値との差分」×2、端は×1の合計となる。

    5       4
  2/ \2   1/ \1
-------------------3
 /1   2\ /2   0\
2       1       3

なので、1回しかカウントされない端に、中央値に近い2数を持ってくれば、それが最大となる。

N が奇数の時は中央値に近い2数が2通り考えられるので、両方試す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import sys
 
n = int(input())
aaa = [int(line) for line in sys.stdin.readlines()]
aaa.sort()
if n % 2 == 0:
    m1, m2 = aaa[n // 2 - 1], aaa[n // 2]
    mid = sum(abs(a - m1) for a in aaa)
    ans = mid * 2 - (m2 - m1)
else:
    m1, m2, m3 = aaa[n // 2 - 1], aaa[n // 2], aaa[n // 2 + 1]
    mid = sum(abs(a - m2) for a in aaa)
    ans = mid * 2 - min(m2 - m1, m3 - m2)
print(ans)

D - Crossing

問題

  • 整数 N が与えられる
  • {1,2,...,N} の部分集合の組み合わせ (S1,S2,...,Sk) を考える
  • 以下の条件を満たすものが存在するか判定し、 存在する場合はひとつ構成せよ
    • 1,2,...,N のうちどの整数も、S1,S2,...,Sk のうちちょうど2つに含まれる
    • S1,S2,...,Sk のどの2つの集合をとっても、それらに共通して含まれる要素はちょうど1つである

N=6
    1 2 3 4 5 6
S1  o o o
S2  o     o o
S3    o   o   o
S4      o   o o
  • どの整数も、ちょうど2つの集合に含まれる(縦に見た時に、同じ列の'o'はどれも2つ)
  • どの集合も、共通要素はちょうど1つ

解法

まず、適当に大きな N を考えて、S1 をたとえば{1,2,3,4}の4つの要素からなるとする。すると、

  • 1を含む集合はあと1つ
  • 2を含む集合はあと1つ
  • 3を含む集合はあと1つ
  • 4を含む集合はあと1つ
  • 上記4つは全て別々の集合(でないと共通要素が2つになってしまう)
  • それ以外に集合は作れない(でないとS1との共通要素が0になってしまう)

よって、作る集合の数は5つでないといけないと分かる。

次に各集合の要素数を考える。たとえば上で「1を含むもう1つの集合」の要素数が5だったりすると、今度はその集合をメインに同じことを考えると、作る集合の数は6にならないといけなくなり、矛盾する。よって、集合の要素数は全て同じ。

一般化すると、

  • 全ての集合の要素数は同じ
  • 1つの集合の要素数を k とすると、作る集合の数は k+1
  • 全集合をまとめた k(k+1) 個の数字に各整数は2個ずつ現れるので、N=k(k+1)/2

この形で表せない N は不可能とわかる。

そこまでわかれば、割り振り方を実験してみる。N ではなく k を基準にして考えてみる。

k=4
   1 2 3 4 5 6 7 8 9 10
S1 o o o o
S2 o       あと3つ
S3   o     あと3つ
S4     o   あと3つ
S5       o あと3つ

これを見ると、S2S5 で残された各あと3つの決め方は、k=3 の時と全く同じ方法が使えることに気付く。

   1 2 3 4 5 6 7 ...
S1 o o o o
S2 o       o o o
S3   o     o     あと2つ
S4     o     o   あと2つ
S5       o     o あと2つ

さらに k=3 の決め方は k=2 に分解できる。

   1 2 3 4 5 6 7 8 9 10
S1 o o o o
S2 o       o o o
S3   o     o     o o
S4     o     o   o   o
S5       o     o   o o

よって、N=k(k+1)/2 で表せさえすれば、再帰的に割り振り方が存在すると言える。

具体的に各集合の数字を書き出してみると、

N = 15
 1  2  3  4  5 |  o-----------o
 1  6  7  8  9 |  o  o--------o
 2  6 10 11 12 |  |  o  o-----o
 3  7 10 13 14 |  |  |  o  o--o
 4  8 11 13 15 |  |  |  |  o  o
 5  9 12 14 15 |  o  o  o  o  o

なので (k+1)×k の配列に順に埋めていけばいい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def check(n):
    i = 1
    while n > 0:
        n -= i
        if n == 0:
            return i
        i += 1
    return False
 
 
def solve(n):
    k = check(n)
    if k == False:
        print('No')
        return
    buf = [[k] + [0] * k for _ in range(k + 1)]
    t = k
    u = 1
    for i in range(k):
        buf[i][i + 1:i + t + 1] = list(range(u, u + t))
        for j in range(t):
            buf[i + j + 1][i + 1] = u + j
        u += t
        t -= 1
    print('Yes')
    print(k + 1)
    print('\n'.join(' '.join(map(str, b)) for b in buf))
 
 
n = int(input())
solve(n)

E - Equilateral

問題

解法

1
 

programming_algorithm/contest_history/atcoder/2018/1027_tenka1_2018.txt · 最終更新: 2018/10/29 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0