Problem p02703 (C++) — buggy submission, verdict: Time Limit Exceeded

// TLEになる
#include <bits/stdc++.h>
using namespace std;

const long long INF = 10000000000000007;
const int MAX_A = 51;
const int MAX_N = 51;

struct edge {
  int to;
  int a;
  long long b;
  edge(int _to, int _a, long long _b) : to(_to), a(_a), b(_b) {}
};

typedef pair<int, int> P;

int main() {
  int N, M, S;
  cin >> N >> M >> S;
  vector<vector<edge>> G(N);
  vector<long long> C(N), D(N);
  long long SumA = 0;
  for (int i = 0; i < M; ++i) {
    int u, v, a, b;
    cin >> u >> v >> a >> b;
    --u, --v;
    G[u].push_back(edge(v, a, b));
    G[v].push_back(edge(u, a, b));
    SumA += a;
  }
  for (int i = 0; i < N; ++i) {
    cin >> C[i] >> D[i];
  }

  // 各町ごとに、銀貨の枚数が0 ~ Amax×(N-1)
  vector<vector<long long>> State(N, vector<long long>(SumA + 1, INF));
  priority_queue<P, vector<P>, greater<P>> que;

  // que.second = K -> i = K/(Amax*(N-1) + 1), j = K%(Amax*(N-1) + 1)
  int Row_size = SumA + 1;
  S = min((long long)S, SumA); // 銀貨をAmax*(N-1)枚になるまで捨てる
  State[0][S] = 0;
  que.push(P(0, Row_size * 0 + S));
  while (!que.empty()) {
    P q = que.top();
    que.pop();
    int City = q.second / Row_size;
    long long Money = q.second - City * Row_size;
    if (State[City][Money] < q.first)
      continue;
    for (int i = 0; i < G[City].size(); ++i) {
      edge e = G[City][i];
      // 購入するときの遷移 (多分ここでTLEになってそう)
      for (int j = 1;; ++j) {
        // j := 交換する金貨
        // 消費する時間は j*D[City]
        // 得られる銀貨は j*C[City]
        long long nM = min(SumA, Money + C[City] * j);
        if (State[City][nM] > State[City][Money] + D[City] * j) {
          State[City][nM] = State[City][Money] + D[City] * j;
          que.push(P(State[City][nM], City * Row_size + nM));
        } else {
          break;
        } // 基本的に、同じ頂点に対して、お金を増やす遷移をして、ある程度お金を増やしたら効果はなくなると考えられる
        if (nM >= SumA)
          break;
      }
      // 移動するときの遷移
      long long nM = Money - e.a;
      if (nM < 0)
        continue;
      if (State[e.to][nM] > State[City][Money] + e.b) {
        State[e.to][nM] = State[City][Money] + e.b;
        que.push(P(State[e.to][nM], e.to * Row_size + nM));
      }
    }
  }
  for (int i = 1; i < N; ++i) {
    auto &p = State[i];
    cout << *min_element(p.begin(), p.end()) << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

// TLEになる
#include <bits/stdc++.h>
using namespace std;

const long long INF = 10000000000000007;
const int MAX_A = 51;
const int MAX_N = 51;

struct edge {
  int to;
  int a;
  long long b;
  edge(int _to, int _a, long long _b) : to(_to), a(_a), b(_b) {}
};

typedef pair<int, int> P;

int main() {
  int N, M, S;
  cin >> N >> M >> S;
  vector<vector<edge>> G(N);
  vector<long long> C(N), D(N);
  long long SumA = 0;
  for (int i = 0; i < M; ++i) {
    int u, v, a, b;
    cin >> u >> v >> a >> b;
    --u, --v;
    G[u].push_back(edge(v, a, b));
    G[v].push_back(edge(u, a, b));
    SumA += a;
  }
  for (int i = 0; i < N; ++i) {
    cin >> C[i] >> D[i];
  }

  // 各町ごとに、銀貨の枚数が0 ~ Amax×(N-1)
  vector<vector<long long>> State(N, vector<long long>(SumA + 1, INF));
  priority_queue<P, vector<P>, greater<P>> que;

  // que.second = K -> i = K/(Amax*(N-1) + 1), j = K%(Amax*(N-1) + 1)
  int Row_size = SumA + 1;
  S = min((long long)S, SumA); // 銀貨をAmax*(N-1)枚になるまで捨てる
  State[0][S] = 0;
  que.push(P(0, Row_size * 0 + S));
  while (!que.empty()) {
    P q = que.top();
    que.pop();
    int City = q.second / Row_size;
    long long Money = q.second - City * Row_size;
    if (State[City][Money] < q.first)
      continue;
    for (int i = 0; i < G[City].size(); ++i) {
      edge e = G[City][i];
      // 購入するときの遷移
      for (int j = 1;; ++j) {
        // j := 交換する金貨
        // 消費する時間は j*D[City]
        // 得られる銀貨は j*C[City]
        long long nM = min(SumA, Money + C[City] * j);
        if (State[City][nM] > State[City][Money] + D[City] * j) {
          State[City][nM] = State[City][Money] + D[City] * j;
          que.push(P(State[City][nM], City * Row_size + nM));
        }
        if (nM >= SumA)
          break;
      }
      // 移動するときの遷移
      long long nM = Money - e.a;
      if (nM < 0)
        continue;
      if (State[e.to][nM] > State[City][Money] + e.b) {
        State[e.to][nM] = State[City][Money] + e.b;
        que.push(P(State[e.to][nM], e.to * Row_size + nM));
      }
    }
  }
  for (int i = 1; i < N; ++i) {
    auto &p = State[i];
    cout << *min_element(p.begin(), p.end()) << endl;
  }
  return 0;
}