No.3278 Avoid Division
レベル : / 実行時間制限 : 1ケース 2.000秒 / メモリ制限
: 512 MB / スペシャルジャッジ問題 (複数の解が存在する可能性があります)
タグ : / 解いたユーザー数 31
作問者 :
とりゐ
/ テスター :
AngrySadEight
タグ : / 解いたユーザー数 31
作問者 :


問題文最終更新日: 2025-09-19 17:31:37
問題文
素数 $P$ と $\mathrm{mod}\ P$ における足し算・掛け算・割り算をおこなうことができるプログラミング言語があります.$P$ は入力では与えられず,$10^8\lt P\lt 10^9$ を満たします.($P$ は事前に決定されています.)
この言語を用いて,高々 $100$ 回の足し算と高々 $100$ 回の掛け算と高々 $1$ 回の割り算を行うことで,以下の問題の答えを求めるプログラムを作成してください.
$N$ 個の演算の命令,および変数 $x$ があります.初め,$x=0$ で初期化されています.今から $i=1,2,\ldots,N$ に対して以下の操作を順番に行います.これらの操作を行った後の $x$ の値を求めてください.
- $op_i=$
+
のとき
$x$ を $x + A_i\pmod P$ で置き換える $(1\leq A_i\lt 10^8)$- $op_i=$
*
のとき
$x$ を $x \times A_i\pmod P$ で置き換える $(1\leq A_i\lt 10^8)$- $op_i=$
/
のとき
$x$ を $x / A_i\pmod P$ で置き換える $(1\leq A_i\lt 10^8)$
- ここで,$a/b\pmod P\ (0\leq a\lt P, 1\leq b\lt P)$ とは $a\equiv bc\pmod P$ を満たす唯一の整数 $c\ (0\leq c\lt P)$ である.
プログラムの仕様
このプログラムでは英小文字で表される $a,b,\ldots,z$ の $26$ 個の変数を扱うことができる.各変数には $0$ 以上 $P$ 未満の整数値を保持することができる.
プログラムの実行開始時点では,すべての変数に $0$ が代入されている.
また,プログラムの開始時点に長さ $N$ の配列 $A$ が与えられ,この配列を参照することができる.(配列の値を変更することはできない.)
プログラムの実行終了時点で変数 $a$ に答えの値が保持されている必要がある.
プログラムの形式
プログラムの $1$ 行目にはプログラムの命令数を表す整数 $M(\geq 0)$ が書かれる. プログラムの $2$ 行目から $M+1$ 行目には $M$ 個の命令が書かれる.命令は上から下に順次実行される.命令は次の $3$ つのいずれかである.
-
add X Y Z
- $X$ に $Y+Z \pmod P$ を代入する.ここで $X$ は変数,$Y,Z$ は変数または配列 $A$ の要素である
-
mul X Y Z
- $X$ に $Y\times Z \pmod P$ を代入する.ここで $X$ は変数,$Y,Z$ は変数または配列 $A$ の要素である
-
div X Y Z
- $X$ に $Y/Z \pmod P$ を代入する.ここで $X$ は変数,$Y,Z$ は変数または配列 $A$ の要素であり,$Z\neq 0$ を満たす必要がある
A[i]
のように記述すること.
プログラム実行コード
コードテスト等で上のプログラムが動作します.ご利用ください.プログラム実行コード(130 行程度あります.)
P = 998244353
import re
import sys
pattern = re.compile(r"A\[(\-?\d+)\]$")
def parse_A(s: str):
m = pattern.fullmatch(s)
if m:
return True, int(m.group(1))
else:
return False, None
def is_lowercase_letter(s: str) -> bool:
return len(s) == 1 and "a" <= s <= "z"
def add(x, y):
return (x + y) % P
def mul(x, y):
return x * y % P
def div(x, y):
if y == 0:
assert False, "Division by zero is not allowed"
return x * pow(y, P - 2, P) % P
n = int(input())
op = [""] * (n + 1)
A = [0] * (n + 1)
for i in range(1, n + 1):
op[i], A[i] = input().split()
A[i] = int(A[i])
x = 0
for i in range(1, n + 1):
if op[i] == "+":
x = add(x, A[i])
elif op[i] == "*":
x = mul(x, A[i])
elif op[i] == "/":
x = div(x, A[i])
else:
print("op[{}] is not '+', '*' and '/'".format(i))
assert 0
vals = {}
for i in range(26):
vals[chr(97 + i)] = 0
m = int(input())
if m < 0:
print("M must be 0 or positive.")
assert 0
add_count = 0
mul_count = 0
div_count = 0
for i in range(1, m + 1):
OP, X, Y, Z = input().split()
Yval = 0
if not is_lowercase_letter(X):
print("X[{}] is invalid format.".format(i))
assert 0
if is_lowercase_letter(Y):
Yval = vals[Y]
else:
valid, val = parse_A(Y)
if not valid:
print("Y[{}] is invalid format.".format(i))
assert 0
else:
if not 1 <= val <= n:
print("Y[{}] is invalid format.".format(i))
assert 0
Yval = A[val]
Zval = 0
if is_lowercase_letter(Z):
Zval = vals[Z]
else:
valid, val = parse_A(Z)
if not valid:
print("Z[{}] is invalid format.".format(i))
assert 0
else:
if not 1 <= val <= n:
print("Z[{}] is invalid format.".format(i))
assert 0
Zval = A[val]
if OP == "add":
vals[X] = add(Yval, Zval)
add_count += 1
elif OP == "mul":
vals[X] = mul(Yval, Zval)
mul_count += 1
elif OP == "div":
vals[X] = div(Yval, Zval)
div_count += 1
else:
print("OP[{}] is invalid format.".format(i))
assert 0
rest = sys.stdin.read().strip()
if rest:
print("Unexpected extra input")
assert 0
if add_count > 100:
print("number of add is greater than 100")
assert 0
if mul_count > 100:
print("number of mul is greater than 100")
assert 0
if div_count > 1:
print("number of div is greater than 1")
assert 0
print("Problem answer : {}".format(x))
print("Program 'a' : {}".format(vals["a"]))
使い方
コードは Python で動作します. 問題の入力とプログラムの命令を順につなげたものを,Python のコードに入力として渡してください.Python コード冒頭の $P$ は好きな素数に置き換えられます.
サンプルの例
4 + 1 * 2 / 3 + 4 4 add b A[1] b mul c A[2] b div d c A[3] add a A[4] d
入力
$N$ $op_1\ A_1$ $\vdots$ $op_N\ A_N$
- $1\leq N\leq 100$
- $op_i$ は
+
,*
,/
のいずれか - $1\leq A_i\lt 10^8$
- $N,A_i$ は整数
出力
問題文に書かれている仕様・形式に従ったプログラムを出力せよ.
サンプル
サンプル1
入力
4 + 1 * 2 / 3 + 4
出力
4 add b A[1] b mul c A[2] b div d c A[3] add a A[4] d
$P=998244353$ だった場合を考えます.
問題の答えは次のようになります.
- はじめ,$x=0$ で初期化されています.
- $i=1$ では,$x$ は $x+A_1\equiv 0+1\equiv1\pmod {998244353}$ になります.
- $i=2$ では,$x$ は $x\times A_2\equiv 1\times 2\equiv2 \pmod {998244353}$ になります.
- $i=3$ では,$x$ は $x/A_3\equiv 2/3\equiv 665496236 \pmod {998244353}$ になります.
- $i=4$ では,$x$ は $x+A_4\equiv 4+665496236\equiv 665496240\pmod {998244353}$ になります.
- 最終的に $x=665496240$ となります.
- はじめ,$a=b=c=\ldots=0$ で初期化されています.
- $1$ 個目の命令では,$b$ は $A_1+b \equiv1+0\equiv 1\pmod {998244353}$ になります.
- $2$ 個目の命令では,$c$ は $A_2\times b\equiv 2\times 1\equiv2 \pmod {998244353}$ になります.
- $3$ 個目の命令では,$d$ は $c/A_3\equiv2/3\equiv 665496236 \pmod {998244353}$ になります.
- $4$ 個目の命令では,$a$ は $A_4+d\equiv4+665496236\equiv 665496240\pmod {998244353}$ になります.
- 最終的に $a=665496240$ となります.
提出するには、Twitter 、GitHub、 Googleもしくは右上の雲マークをクリックしてアカウントを作成してください。