Official

C - 魔法陣の反転 / Inversion of the Magic Square Editorial by kyopro_friends


ポーランド記法で書かれた数式は、以下のアルゴリズムにより、スタックを用いて線形時間で計算することができます。

擬似コード

function eval(tokens):
  stack = ()
  for t in tokens:
    stack.push(t)
    while stackの末尾が後ろから順に「数値」「数値」「演算子」:
      b = stack.pop()
      a = stack.pop()
      op = stack.pop()
      result = op(a, b)
      stack.push(result)
  return stack.pop()

このアルゴリズムを用いて、変化前後の 2 個の数式を実際に評価すればよいです。計算量は \(O(N)\) です。言語によっては、負の数の除算の丸め方向に注意してください。

実装例 (C++)

#include<bits/stdc++.h>
using namespace std;

bool is_op(string token){
  return token == "+" || token == "-" || token == "*" || token == "/";
}

int main() {
  int n;
  cin >> n;
  vector<string> t(n);
  for(int i=0; i<n; i++) cin >> t[i];
  int k;
  cin >> k;
  vector<int> p(k);
  for(int i=0; i<k; i++){
    cin >> p[i];
    p[i]--;
  }

  auto solve = [&](vector<string> t){
     vector<string> s;
     for(auto token: t){
       s.push_back(token);
       while(s.size() >=3 && !is_op(s[s.size()-1]) && !is_op(s[s.size()-2]) && is_op(s[s.size()-3])){
         string b = s.back(); s.pop_back();
         string a = s.back(); s.pop_back();
         string op = s.back(); s.pop_back();
         if(op == "+"){
           s.push_back(to_string(stoll(a) + stoll(b)));
         }else if(op == "-"){
           s.push_back(to_string(stoll(a) - stoll(b)));
         }else if(op == "*"){
           s.push_back(to_string(stoll(a) * stoll(b)));
         }else if(op == "/"){
           s.push_back(to_string(stoll(a) / stoll(b)));
         }
       }
     }
     return stoll(s.back());
  };
  
  cout << solve(t) << endl;
  for(auto i: p){
    if(t[i] == "+"){
      t[i] = "-";
    }else if(t[i] == "-"){
      t[i] = "+";
    }else if(t[i] == "*"){
      t[i] = "/";
    }else if(t[i] == "/"){
      t[i] = "*";
    }
  }
  cout << solve(t) << endl;
}

実装例 (Python)

def is_op(t):
  return t == '+' or t == '-' or t == '*' or t == '/'

N = int(input())
T = []
for token in input().split():
  if is_op(token):
    T.append(token)
  else:
    T.append(int(token))
K = int(input())
if K > 0:
  P = list(map(int, input().split()))
  P = [p - 1 for p in P]
else:
  P = []

def my_div(a, b):
  if (a < 0) ^ (b < 0):
    return - ((-a) // b)
  return a // b

def solve(T):
  stack = []
  for t in T:
    stack.append(t)
    while len(stack) >= 3 and not is_op(stack[-1]) and not is_op(stack[-2]) and is_op(stack[-3]):
      b = stack.pop()
      a = stack.pop()
      op = stack.pop()
      if op == '+':
        stack.append(a + b)
      elif op == '-':
        stack.append(a - b)
      elif op == '*':
        stack.append(a * b)
      elif op == '/':
        stack.append(my_div(a, b))
  return stack.pop()

print(solve(T))
for p in P:
  if T[p] == '+':
    T[p] = '-'
  elif T[p] == '-':
    T[p] = '+'
  elif T[p] == '*':
    T[p] = '/'
  elif T[p] == '/':
    T[p] = '*'
print(solve(T))

posted:
last update: