Problem p01555 (C++) — buggy submission, verdict: Runtime Error


// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2441

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>

#define ALL(v) (v).begin(), (v).end()
#define REP(i, p, n) for (int i = p; i < (int)(n); ++i)
#define rep(i, n) REP(i, 0, n)
#define dump(a) (cerr << #a << "=" << (a) << endl)
#define DUMP(list)                                                             \\
  cout << "{ ";                                                                \\
  for (auto nth : list) {                                                      \\
    cout << nth << " ";                                                        \\
  }                                                                            \\
  cout << "}" << endl;

using namespace std;

typedef long long ll;

const ll INF = 1e18;

ll normal_count(ll cur, ll prev) {
  return cur - (cur / 3 + cur / 5 - cur / 15) -
         (prev - (prev / 3 + prev / 5 - prev / 15));
}

ll fizzbuzz_count(ll cur, ll prev) {
  return cur / 3 + cur / 5 - prev / 3 - prev / 5;
}

ll word_count(ll cur, ll prev, ll digit) {
  ll normal = digit * normal_count(cur, prev);
  ll fizzbuzz = 4 * fizzbuzz_count(cur, prev);
  return normal + fizzbuzz;
}

int main() {
  ll s;
  cin >> s;

  ll total = 0;
  ll cur = 0, prev = 0, digit = 1;
  while (true) {
    cur = pow(10, digit) - 1;
    ll len = word_count(cur, prev, digit); // n桁の区間の文字数を取得
    if (total + len >= s)
      break;
    total += len;
    prev = cur;
    digit += 1;
  }

  ll left = prev + 1, right = cur;
  ll mid, len;
  while (right > left) {
    mid = (left + right) / 2;
    len = word_count(mid, prev, digit) + total;
    if (len < s) {
      left = mid + 1;
    } else if (len > s) {
      right = mid - 1;
    } else {
      right = left = mid;
    }
  }

  len = word_count(left, prev, digit) + total;
  if (left % 3 == 0)
    len -= 4;
  if (left % 5 == 0)
    len -= 4;
  if (left % 3 != 0 && left % 5 != 0)
    len -= digit;

  ll base = s - len - 1;
  string ans = "";

  for (ll i = left; ans.size() < 20 + base; ++i) {
    if (i % 3 == 0)
      ans += "Fizz";
    if (i % 5 == 0)
      ans += "Buzz";
    if (i % 3 != 0 && i % 5 != 0)
      ans += to_string(i);
  }

  cout << ans.substr(base, 20) << endl;

  return 0;
}

Error: 0

Fixed submission:


// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2441

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>

#define ALL(v) (v).begin(), (v).end()
#define REP(i, p, n) for (int i = p; i < (int)(n); ++i)
#define rep(i, n) REP(i, 0, n)
#define dump(a) (cerr << #a << "=" << (a) << endl)
#define DUMP(list)                                                             \\
  cout << "{ ";                                                                \\
  for (auto nth : list) {                                                      \\
    cout << nth << " ";                                                        \\
  }                                                                            \\
  cout << "}" << endl;

using namespace std;

typedef long long ll;

const ll INF = 1e18;

ll normal_count(ll cur, ll prev) {
  return cur - (cur / 3 + cur / 5 - cur / 15) -
         (prev - (prev / 3 + prev / 5 - prev / 15));
}

ll fizzbuzz_count(ll cur, ll prev) {
  return cur / 3 + cur / 5 - prev / 3 - prev / 5;
}

ll word_count(ll cur, ll prev, ll digit) {
  ll normal = digit * normal_count(cur, prev);
  ll fizzbuzz = 4 * fizzbuzz_count(cur, prev);
  return normal + fizzbuzz;
}

int main() {
  ll s;
  cin >> s;

  ll total = 0;
  ll cur = 0, prev = 0, digit = 1;
  while (true) {
    cur = pow(10, digit) - 1;
    ll len = word_count(cur, prev, digit); // n桁の区間の文字数を取得
    if (total + len >= s)
      break;
    total += len;
    prev = cur;
    digit += 1;
  }

  ll left = prev + 1, right = cur;
  ll mid, len;
  while (right > left) {
    mid = (left + right) / 2;
    len = word_count(mid, prev, digit) + total;
    if (len < s) {
      left = mid + 1;
    } else if (len > s) {
      right = mid - 1;
    } else {
      right = left = mid;
    }
  }

  len = word_count(left, prev, digit) + total;
  if (left % 3 == 0)
    len -= 4;
  if (left % 5 == 0)
    len -= 4;
  if (left % 3 != 0 && right % 5 != 0)
    len -= digit;

  ll base = s - len - 1;
  string ans = "";
  for (ll i = left; ans.size() < 20 + base; ++i) {
    if (i % 3 == 0)
      ans += "Fizz";
    if (i % 5 == 0)
      ans += "Buzz";
    if (i % 3 != 0 && i % 5 != 0)
      ans += to_string(i);
  }

  cout << ans.substr(base, 20) << endl;

  return 0;
}