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

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

typedef long long ll;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define FOR(i, l, r) for (ll i = (l); i < (r); i++)
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
const ll INF = 1LL << 60;
const int inf = 1001001001;
const ll mod = 1000000007;
using pp = pair<ll, ll>;

// union by size + path having
class UnionFind {
public:
  vector<ll> par; // 各元の親を表す配列
  vector<ll> siz; // 素集合のサイズを表す配列(1 で初期化)

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }
  void init(ll sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL); // resize だとなぜか初期化されなかった
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }

  // Member Function
  // Find
  ll root(ll x) { // 根の検索
    while (par[x] != x) {
      x = par[x] = par[par[x]]; // x の親の親を x の親とする
    }
    return x;
  }

  // Union(Unite, Merge)
  bool unite(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    // merge technique（データ構造をマージするテク．小を大にくっつける)
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool same(ll x, ll y) { // 連結判定
    return root(x) == root(y);
  }

  ll size(ll x) { // 素集合のサイズ
    return siz[root(x)];
  }
};

ll modpow(ll x, ll n) {
  x = x % mod;
  if (n == 0)
    return 1; // 再帰の終了条件

  else if (n % 2 == 1) {
    return (x * modpow(x, n - 1)) % mod; // nが奇数ならnを1ずらす
  } else
    return modpow((x * x) % mod, n / 2) % mod; // nが偶数ならnが半分になる
}

ll com(ll n, ll k) {
  ll x = 1;
  for (int i = n - k + 1; i <= n; i++) {
    x = x * i % mod;
  }

  ll y = 1;
  for (int i = 1; i <= k; i++) {
    y = y * i % mod;
  }
  y = modpow(y, mod - 2);

  return x * y % mod;
}

bool is_prime(const unsigned n) {
  switch (n) {
  case 0: // fall-through
  case 1:
    return false;
  case 2: // fall-through
  case 3:
    return true;
  } // n > 3 が保証された

  if (n % 2 == 0 || n % 3 == 0)
    return false;
  // n は 2 と 3 のいずれの倍数でもないことが保証された
  // これより n は (6の倍数)-1 か (6の倍数)+1 である

  // 6の倍数前後の数を使って試し割りをする
  for (unsigned i = 5; i * i <= n; i += 6) {
    if (n % i == 0)
      return false; // (6の倍数)-1
    if (n % (i + 2) == 0)
      return false; // (6の倍数)+1
  }

  return true;
}

int digsum(int n) {
  int res = 0;
  while (n > 0) {
    res += n % 10; // ここをres++;に変えたら桁数を求める関数になる
    n /= 10;
  }
  return res;
}
vector<ll> divisor(ll n) {
  vector<ll> ret;
  for (ll i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      ret.push_back(i);
      if (i * i != n)
        ret.push_back(n / i);
    }
  }
  sort(ret.begin(), ret.end());
  return ret;
}

int main() {

  ll n, k;
  cin >> n >> k;
  vector<ll> a(n, 0);
  rep(i, n) { cin >> a[i]; }
  rep(i, k) {
    vector<ll> b(n + 1, 0);
    rep(j, n) {
      ll l = max(j - a[j], 0LL);
      ll r = min(n, j + a[j] + 1);
      b[l]++;
      b[r]--;
    }
    rep(j, n) b[j + 1] += b[j];
    b.pop_back();
    if (a == b)
      break;
    a = b;
  }
  rep(j, n) {
    if (j == n - 1)
      cout << a[j] << endl;
    else
      cout << a[j] << " ";
  }
}


Error: TLE

Fixed submission:

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

typedef long long ll;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define FOR(i, l, r) for (ll i = (l); i < (r); i++)
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
const ll INF = 1LL << 60;
const int inf = 1001001001;
const ll mod = 1000000007;
using pp = pair<ll, ll>;

// union by size + path having
class UnionFind {
public:
  vector<ll> par; // 各元の親を表す配列
  vector<ll> siz; // 素集合のサイズを表す配列(1 で初期化)

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }
  void init(ll sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL); // resize だとなぜか初期化されなかった
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }

  // Member Function
  // Find
  ll root(ll x) { // 根の検索
    while (par[x] != x) {
      x = par[x] = par[par[x]]; // x の親の親を x の親とする
    }
    return x;
  }

  // Union(Unite, Merge)
  bool unite(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    // merge technique（データ構造をマージするテク．小を大にくっつける)
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool same(ll x, ll y) { // 連結判定
    return root(x) == root(y);
  }

  ll size(ll x) { // 素集合のサイズ
    return siz[root(x)];
  }
};

ll modpow(ll x, ll n) {
  x = x % mod;
  if (n == 0)
    return 1; // 再帰の終了条件

  else if (n % 2 == 1) {
    return (x * modpow(x, n - 1)) % mod; // nが奇数ならnを1ずらす
  } else
    return modpow((x * x) % mod, n / 2) % mod; // nが偶数ならnが半分になる
}

ll com(ll n, ll k) {
  ll x = 1;
  for (int i = n - k + 1; i <= n; i++) {
    x = x * i % mod;
  }

  ll y = 1;
  for (int i = 1; i <= k; i++) {
    y = y * i % mod;
  }
  y = modpow(y, mod - 2);

  return x * y % mod;
}

bool is_prime(const unsigned n) {
  switch (n) {
  case 0: // fall-through
  case 1:
    return false;
  case 2: // fall-through
  case 3:
    return true;
  } // n > 3 が保証された

  if (n % 2 == 0 || n % 3 == 0)
    return false;
  // n は 2 と 3 のいずれの倍数でもないことが保証された
  // これより n は (6の倍数)-1 か (6の倍数)+1 である

  // 6の倍数前後の数を使って試し割りをする
  for (unsigned i = 5; i * i <= n; i += 6) {
    if (n % i == 0)
      return false; // (6の倍数)-1
    if (n % (i + 2) == 0)
      return false; // (6の倍数)+1
  }

  return true;
}

int digsum(int n) {
  int res = 0;
  while (n > 0) {
    res += n % 10; // ここをres++;に変えたら桁数を求める関数になる
    n /= 10;
  }
  return res;
}
vector<ll> divisor(ll n) {
  vector<ll> ret;
  for (ll i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      ret.push_back(i);
      if (i * i != n)
        ret.push_back(n / i);
    }
  }
  sort(ret.begin(), ret.end());
  return ret;
}

int main() {

  ll n, k;
  cin >> n >> k;
  vector<ll> light(n + 1);
  vector<ll> num(n + 1, 0);
  FOR(i, 0, n + 1) {
    if (i == 0)
      continue;
    cin >> light[i];
  }

  if (k >= 50)
    k = 50;
  while (k > 0) {
    FOR(j, 1, n + 1) {
      ll a = max(j - light[j], 0LL);
      ll b = min(n, j + light[j]);
      for (ll l = a; l <= b; l++) {
        num[l]++;
      }
    }

    FOR(j, 1, n + 1) { light[j] = num[j]; }
    k--;
    fill(num.begin(), num.end(), 0);
  }

  FOR(i, 1, n + 1) {
    if (i == n)
      cout << light[i] << endl;
    else
      cout << light[i] << " ";
  }
}