公式

H - Guess the Sum 解説 by toam


質問できる区間がセグメント木のような区間になっている点で ABC349-D Divide Interval と似ています.本問題との違いは引き算が行えることです.例えば \(N=3,L=1,R=7\) のとき,質問する区間を ABC349-D の方法で区間を分割すると\(A_1,A_2+A_3,A_4+A_5+A_6+A_7\)\(3\) 回の質問が必要になります.一方で,本問題では一回目に \(A_0+A_1+A_2+A_3+A_4+A_5+A_6+A_7\) を,二回目に \(A_0\) を質問し,一回目の値から二回目の値を引くことで答えを求めることができます.


以下では,合同式の法を \(100\) とします.

整数 \(x,y(0\leq x,y\leq 2^N)\) に対して,\(S(x,y)\) を次で定めます.

\[ S(x,y)\equiv \begin{cases} 0\ (x=y) \\ \displaystyle\left( \sum_{i=x}^{y-1} A_i\right)\ (x<y)\\ -S(y,x)\ (x>y) \end{cases}\]

求めるものは \(S(L,R+1)\),質問できるものは \(S\left(2^ij,2^i(j+1)\right)\) です.また,\(S\left(2^i(j+1),2^ij\right)\equiv-S\left(2^ij,2^i(j+1)\right)\) であるため,\(S\left(2^i(j+1),2^ij\right)\) も質問できるものとみなします.\(S(x,y)\)\(S(y,z)\) が分かってるとき, \(S(x,z)\)\(S(x,y)+S(y,z)\) として求めることができます.

ここで,頂点が \(0,1,\dots,2^N\)\(2^N+1\) 頂点であり,\(S(x,y)\) が質問できるような \(x,y\) に対して頂点 \(x\)\(y\) の間に辺を貼ってあるようなグラフ \(G\) を考えます.

\(G\) 上での距離が \(2\) であるような頂点 \(x,y\) に対して,\(G\) における \(x\) から \(y\) までの最短経路上の頂点を \(v_0(=x),v_1,v_2(=y)\) として \(S(v_0,v_1)\) および \(S(v_1,v_2)\) を質問することで \(S(x,y)\)\(2\) 回の質問で特定することができます.

同様に.\(G\) 上での距離が \(3\) であるような頂点 \(x,y\) に対して,\(G\) における \(x\) から \(y\) までの最短経路上の頂点を \(v_0(=x),v_1,v_2,v_3(=y)\) として \(S(v_0,v_1),S(v_1,v_2)\) および \(S(v_2,v_3)\) を質問することで \(S(x,y)\)\(3\) 回の質問で特定することができます.

より一般に.\(G\) 上での距離が \(d\) であるような頂点 \(x,y\) に対して,\(S(x,y)\)\(d\) 回の質問で求めることができます.

よって,グラフ \(G\) 上で \(L\) から \(R\) の最短経路が(復元付きで)求められれば良いです.グラフ \(G\) の頂点数は \(2^N+1\),辺数は \(2^{N+1}-1\) であるため,BFS を用いることで計算量 \(O(2^N)\) で最短経路を求めることができます.

from collections import deque

N, L, R = map(int, input().split())
n = 1 << N
edge = [[] for i in range(n + 1)]
for i in range(N + 1):
    for l in range(0, n, 1 << i):
        r = l + (1 << i)
        edge[l].append(r)
        edge[r].append(l)

parent = [None] * (n + 1)
parent[R + 1] = -1
dq = deque([R + 1])
while dq:
    v = dq.popleft()
    for u in edge[v]:
        if parent[u] == None:
            parent[u] = v
            dq.append(u)

ans = 0
now = L
while parent[now] != -1:
    p = parent[now]
    sgn = 1
    l, r = now, p
    if l > r:
        sgn = -1
        l, r = r, l
    i = (r - l).bit_length() - 1
    j = l >> i
    print("?", i, j, flush=True)
    T = int(input())
    ans += sgn * T
    now = p

print("!", ans % 100)

投稿日時:
最終更新: