Problem p02653 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define FORE(i, a, b) for (int i = (a); i <= (b); ++i)
#define REPE(i, n) FORE(i, 0, n)
#define FORSZ(i, a, v) FOR(i, a, SZ(v))
#define REPSZ(i, v) REP(i, SZ(v))
std::mt19937
    rnd((int)std::chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

const int MAXN = 5000;
const int MOD = 1000000007;
void inc(int &a, int b) {
  if ((a += b) >= MOD)
    a -= MOD;
}
void dec(int &a, int b) {
  if ((a -= b) < 0)
    a += MOD;
}

int n, alen, blen;

// dp[i][j][k] = number of ways to select a block of i characters ending with
// less than alen zeroes (or empty) with no valid subsequence, followed by a
// block of length j starting with 1 (or at beginning of string) in which all
// subsequences of zeroes have length at least alen, ending with k
int dp[MAXN + 1][MAXN + 1][2];
int dpsum[MAXN + 1][MAXN + 2];
int p2[MAXN + 1];

int solve() {
  p2[0] = 1;
  FORE(i, 1, n) p2[i] = (ll)p2[i - 1] * 2 % MOD;
  if (alen > blen)
    swap(alen, blen);
  REPE(i, n) dpsum[i][0] = dpsum[i][1] = 0;
  REPE(i, n) FORE(j, 1, blen) {
    dp[i][j][0] = dp[i][j][1] = 0;
    FORE(k, alen, j - 1) inc(dp[i][j][0], dp[i][j - k][1]);
    if (i == 0 && j >= alen)
      inc(dp[i][j][0], 1);
    if (j == 1) {
      if (i < alen)
        inc(dp[i][j][1], 1);
      // FORE(k, 1, min(i, alen - 1)) FORE(l, 1, min(blen - 1, i - k))
      // inc(dp[i][j][1], dp[i - k - l][l][1]); FORE(z, 2, i) FORE(k, max(1, z -
      // blen + 1), min(min(i, alen - 1), z - 1)) { int l = z - k;
      // inc(dp[i][j][1], dp[i - z][l][1]); }
      FORE(z, 2, i) {
        int lo = z - min(min(i, alen - 1), z - 1),
            hi = z - max(1, z - blen + 1);
        lo = min(lo, blen);
        hi = min(hi, blen);
        // FORE(l, lo, hi) inc(dp[i][j][1], dp[i - z][l][1]);
        //{ int chk = 0; FORE(l, 0, hi) inc(chk, dp[i - z][l][1]); if (!(chk ==
        //dpsum[i - z][hi + 1])) { printf("err i-z=%d hi+1=%d: %d vs %d\n", i -
        //z, hi + 1, chk, dpsum[i - z][hi + 1]); exit(0); } } { int chk = 0;
        //FORE(l, 0, lo - 1) inc(chk, dp[i - z][l][1]); if (!(chk == dpsum[i -
        //z][lo])) { printf("err i-z=%d lo=%d: %d vs %d [i=%d]\n", i - z, lo,
        //chk, dpsum[i - z][lo],i); exit(0); } }
        inc(dp[i][j][1], dpsum[i - z][hi + 1]);
        dec(dp[i][j][1], dpsum[i - z][lo]);
      }
    } else {
      inc(dp[i][j][1], dp[i][j - 1][0]);
      inc(dp[i][j][1], dp[i][j - 1][1]);
    }
    // printf("dp[%d][%d]: %d / %d\n", i, j, dp[i][j][0], dp[i][j][1]);
    dpsum[i][j + 1] = dpsum[i][j];
    inc(dpsum[i][j + 1], dp[i][j][1]);
    // if (i == 1) printf("dpsum[%d][%d]=%d dp[%d][%d][1]=%d ->
    // dpsum[%d][%d]=%d\n", i, j, dpsum[i][j], i, j, dp[i][j][1], i, j + 1,
    // dpsum[i][j + 1]);
  }
  int ret = 0;
  REPE(i, n - blen) {
    int cur = 0;
    REP(k, 2) inc(cur, dp[i][blen][k]);
    // printf("%d: (%d+%d)*%d\n", i, dp[i][blen][0], dp[i][blen][1], p2[n - i -
    // blen]);
    cur = (ll)cur * p2[n - i - blen] % MOD;
    inc(ret, cur);
  }
  REPE(i, n - blen)
  FORE(j, 1, blen - 1) if (i + j + alen <= n && j + alen > blen) {
    int cur = dp[i][j][1];
    // printf("%d %d: %d * %d\n", i, j, cur, p2[n - i - j - alen]);
    cur = (ll)cur * p2[n - i - j - alen] % MOD;
    inc(ret, cur);
  }
  return ret;
}

void run() {
  scanf("%d%d%d", &n, &alen, &blen);
  printf("%d\n", solve());
}

int solvestupid() {
  int ret = 0;
  assert(alen <= blen);
  REP(mask, 1 << n) {
    bool ok = false;
    REPE(offset, n - blen) {
      int nzero = 0;
      REP(i, n - offset) {
        int cur = (mask >> (offset + i)) & 1;
        if (cur == 0)
          ++nzero;
        if (cur == 1) {
          if (nzero != 0 && nzero < alen)
            break;
          nzero = 0;
        }
        if ((nzero == 0 || nzero >= alen) && i + 1 >= blen)
          ok = true;
      }
    }
    if (ok)
      ++ret;
  }
  return ret;
}

void stress() {
  for (n = 1; n <= 15; ++n)
    for (alen = 1; alen <= n; ++alen)
      for (blen = alen; blen <= n; ++blen) {
        int have = solve();
        int want = solvestupid();
        if (have == want) {
          printf(".");
          continue;
        }
        printf("err %d %d %d: have=%d want=%d\n", n, alen, blen, have, want);
      }
}

int main() {
  // stress();
  run();
  return 0;
}


Fixed submission:
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define FORE(i, a, b) for (int i = (a); i <= (b); ++i)
#define REPE(i, n) FORE(i, 0, n)
#define FORSZ(i, a, v) FOR(i, a, SZ(v))
#define REPSZ(i, v) REP(i, SZ(v))
std::mt19937
    rnd((int)std::chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

const int MAXN = 5000;
const int MOD = 1000000007;
void inc(int &a, int b) {
  if ((a += b) >= MOD)
    a -= MOD;
}
void dec(int &a, int b) {
  if ((a -= b) < 0)
    a += MOD;
}

int n, alen, blen;

// dp[i][j][k] = number of ways to select a block of i characters ending with
// less than alen zeroes (or empty) with no valid subsequence, followed by a
// block of length j starting with 1 (or at beginning of string) in which all
// subsequences of zeroes have length at least alen, ending with k
int dp[MAXN + 1][MAXN + 1][2];
int dpsum[MAXN + 1][MAXN + 2];
int p2[MAXN + 1];

int solve() {
  p2[0] = 1;
  FORE(i, 1, n) p2[i] = (ll)p2[i - 1] * 2 % MOD;
  if (alen > blen)
    swap(alen, blen);
  REPE(i, n) dpsum[i][0] = dpsum[i][1] = 0;
  REPE(i, n) FORE(j, 1, blen) {
    dp[i][j][0] = dp[i][j][1] = 0;
    if (alen <= j - 1) {
      int lo = 1, hi = j - alen;
      // FORE(k, alen, j - 1) inc(dp[i][j][0], dp[i][j - k][1]);
      inc(dp[i][j][0], dpsum[i][hi + 1]);
      dec(dp[i][j][0], dpsum[i][lo]);
    }
    if (i == 0 && j >= alen)
      inc(dp[i][j][0], 1);
    if (j == 1) {
      if (i < alen)
        inc(dp[i][j][1], 1);
      // FORE(k, 1, min(i, alen - 1)) FORE(l, 1, min(blen - 1, i - k))
      // inc(dp[i][j][1], dp[i - k - l][l][1]); FORE(z, 2, i) FORE(k, max(1, z -
      // blen + 1), min(min(i, alen - 1), z - 1)) { int l = z - k;
      // inc(dp[i][j][1], dp[i - z][l][1]); }
      FORE(z, 2, i) {
        int lo = z - min(min(i, alen - 1), z - 1),
            hi = z - max(1, z - blen + 1);
        lo = min(lo, blen);
        hi = min(hi, blen);
        // FORE(l, lo, hi) inc(dp[i][j][1], dp[i - z][l][1]);
        //{ int chk = 0; FORE(l, 0, hi) inc(chk, dp[i - z][l][1]); if (!(chk ==
        //dpsum[i - z][hi + 1])) { printf("err i-z=%d hi+1=%d: %d vs %d\n", i -
        //z, hi + 1, chk, dpsum[i - z][hi + 1]); exit(0); } } { int chk = 0;
        //FORE(l, 0, lo - 1) inc(chk, dp[i - z][l][1]); if (!(chk == dpsum[i -
        //z][lo])) { printf("err i-z=%d lo=%d: %d vs %d [i=%d]\n", i - z, lo,
        //chk, dpsum[i - z][lo],i); exit(0); } }
        inc(dp[i][j][1], dpsum[i - z][hi + 1]);
        dec(dp[i][j][1], dpsum[i - z][lo]);
      }
    } else {
      inc(dp[i][j][1], dp[i][j - 1][0]);
      inc(dp[i][j][1], dp[i][j - 1][1]);
    }
    // printf("dp[%d][%d]: %d / %d\n", i, j, dp[i][j][0], dp[i][j][1]);
    dpsum[i][j + 1] = dpsum[i][j];
    inc(dpsum[i][j + 1], dp[i][j][1]);
    // if (i == 1) printf("dpsum[%d][%d]=%d dp[%d][%d][1]=%d ->
    // dpsum[%d][%d]=%d\n", i, j, dpsum[i][j], i, j, dp[i][j][1], i, j + 1,
    // dpsum[i][j + 1]);
  }
  int ret = 0;
  REPE(i, n - blen) {
    int cur = 0;
    REP(k, 2) inc(cur, dp[i][blen][k]);
    // printf("%d: (%d+%d)*%d\n", i, dp[i][blen][0], dp[i][blen][1], p2[n - i -
    // blen]);
    cur = (ll)cur * p2[n - i - blen] % MOD;
    inc(ret, cur);
  }
  REPE(i, n - blen)
  FORE(j, 1, blen - 1) if (i + j + alen <= n && j + alen > blen) {
    int cur = dp[i][j][1];
    // printf("%d %d: %d * %d\n", i, j, cur, p2[n - i - j - alen]);
    cur = (ll)cur * p2[n - i - j - alen] % MOD;
    inc(ret, cur);
  }
  return ret;
}

void run() {
  scanf("%d%d%d", &n, &alen, &blen);
  printf("%d\n", solve());
}

int solvestupid() {
  int ret = 0;
  assert(alen <= blen);
  REP(mask, 1 << n) {
    bool ok = false;
    REPE(offset, n - blen) {
      int nzero = 0;
      REP(i, n - offset) {
        int cur = (mask >> (offset + i)) & 1;
        if (cur == 0)
          ++nzero;
        if (cur == 1) {
          if (nzero != 0 && nzero < alen)
            break;
          nzero = 0;
        }
        if ((nzero == 0 || nzero >= alen) && i + 1 >= blen)
          ok = true;
      }
    }
    if (ok)
      ++ret;
  }
  return ret;
}

void stress() {
  for (n = 1; n <= 15; ++n)
    for (alen = 1; alen <= n; ++alen)
      for (blen = alen; blen <= n; ++blen) {
        int have = solve();
        int want = solvestupid();
        if (have == want) {
          printf(".");
          continue;
        }
        printf("err %d %d %d: have=%d want=%d\n", n, alen, blen, have, want);
      }
}

int main() {
  // stress();
  run();
  return 0;
}