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

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fi first
#define se second
#define mp make_pair
#define pb push_back

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef unsigned long long ull;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds;

vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = (1e9 + 7);
int add(int a, int b) {
  a += b;
  while (a >= MOD)
    a -= MOD;
  return a;
}
void radd(int &a, int b) { a = add(a, b); }
int mult(int a, int b) { return (a * 1LL * b) % MOD; }
void rmult(int &a, int b) { a = mult(a, b); }
int modpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1)
      r = mult(r, a);
    a = mult(a, a);
    b >>= 1;
  }
  return r;
}
int choose(int a, int b) {
  if (a < b)
    return 0;
  if (b == 0)
    return 1;
  if (a == b)
    return 1;
  return mult(fact[a], mult(ifact[b], ifact[a - b]));
}
int inverse(int a) { return modpow(a, MOD - 2); }
void init(int _n) {
  fact.clear();
  ifact.clear();
  inv.clear();
  pow2.clear();
  fact.resize(_n + 1);
  ifact.resize(_n + 1);
  inv.resize(_n + 1);
  pow2.resize(_n + 1);
  pow2[0] = 1;
  ifact[0] = 1;
  fact[0] = 1;
  for (int i = 1; i <= _n; i++) {
    pow2[i] = add(pow2[i - 1], pow2[i - 1]);
    fact[i] = mult(fact[i - 1], i);
    // ifact[i]=mult(ifact[i-1],inv[i]);
  }
  ifact[_n] = inverse(fact[_n]);
  for (int i = _n - 1; i >= 1; i--) {
    ifact[i] = mult(ifact[i + 1], i + 1);
  }
  for (int i = 1; i <= _n; i++) {
    inv[i] = mult(fact[i - 1], ifact[i]);
  }
}

int ipow2[1111];

int adj[18][18];
int dp[1700000];
int reach[2][(1 << 16)];
int n, m;
int p3[18];
int cntadj[15000000];

int solve(int u, int bit) {
  if (!(bit & (1 << u)))
    return 0;
  if (reach[u][bit] != -1)
    return reach[u][bit];
  int res = 1;
  vi V;
  for (int i = 0; i < n; i++) {
    if (bit & (1 << i))
      V.pb(i);
  }
  if (bit > 0) {
    for (int j = bit;; j = (bit & (j - 1))) {
      if (j == bit)
        continue;
      int coeff = 1;
      int bb = 0;
      for (int x : V) {
        if (j & (1 << x))
          bb += p3[x]; // VV[1].pb(x);
        else
          bb += p3[x] * 2; // VV[0].pb(x);
      }
      coeff = ipow2[cntadj[bb]];
      radd(res, MOD - mult(coeff, solve(u, j)));
      if (j == 0)
        break;
    }
  }
  return (reach[u][bit] = res);
}

int V[18];
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  init(1201);
  for (int i = 0; i <= 1000; i++)
    ipow2[i] = inverse(pow2[i]);
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    adj[u][v] = adj[v][u] = 1;
  }
  p3[0] = 1;
  for (int i = 1; i <= 17; i++)
    p3[i] = p3[i - 1] * 3;
  for (int i = 0; i < 2; i++) {
    memset(reach, -1, sizeof(reach));
    reach[i][(1 << i)] = 1;
  }
  int ans = 0;
  for (int i = 1; i < p3[n]; i++) {
    int cur = i;
    int exv = -1;
    int firstv = -1;
    for (int j = 0; j < n; j++) {
      V[j] = cur % 3;
      cur /= 3;
      if (V[j] != 0) {
        exv = j;
        firstv = V[j];
      }
    }
    cntadj[i] = cntadj[i - firstv * p3[exv]];
    for (int j = 0; j < n; j++) {
      if (V[j] != 0 && V[j] != firstv) {
        cntadj[i] += adj[exv][j];
      }
    }
    // if(i%100000==0) cerr<<"FINISH "<<i<<' '<<p3[n]<<'\\n';
  }
  // cerr<<"HALFWAY DONE"<<endl;
  for (int i = 0; i < p3[n - 2]; i++) {
    V[0] = 1;
    V[1] = 2;
    int cur = i;
    int b2 = 2;
    int b1 = 1;
    for (int j = 2; j < n; j++) {
      V[j] = cur % 3;
      if (V[j] == 1)
        b1 |= (1 << j);
      if (V[j] == 2)
        b2 |= (1 << j);
      cur /= 3;
    }
    int bb = 0;
    for (int j = 0; j < n; j++) {
      if (b1 & (1 << j))
        bb += p3[j];
      if (b2 & (1 << j))
        bb += 2 * p3[j];
    }
    if (cntadj[bb] > 0)
      continue;
    bb = 0;
    for (int j = 0; j < n; j++) {
      if (b1 & (1 << j))
        bb += p3[j];
      else if (b2 & (1 << j))
        bb += p3[j];
      else
        bb += 2 * p3[j];
    }
    /*
    for(int x:V[0])
    {
            for(int y:V[1]) cnt_edge+=adj[x][y];
            for(int y:V[2]) cnt_edge+=adj[x][y];
    }
    */
    int cnt_edge = cntadj[bb];
    ans = add(ans, mult(pow2[m - cnt_edge], mult(solve(0, b1), solve(1, b2))));
  }
  ans = add(pow2[m], MOD - ans);
  cout << ans << '\\n';
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fi first
#define se second
#define mp make_pair
#define pb push_back

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef unsigned long long ull;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds;

vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = (1e9 + 7);
int add(int a, int b) {
  a += b;
  while (a >= MOD)
    a -= MOD;
  return a;
}
void radd(int &a, int b) { a = add(a, b); }
int mult(int a, int b) { return (a * 1LL * b) % MOD; }
void rmult(int &a, int b) { a = mult(a, b); }
int modpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1)
      r = mult(r, a);
    a = mult(a, a);
    b >>= 1;
  }
  return r;
}
int choose(int a, int b) {
  if (a < b)
    return 0;
  if (b == 0)
    return 1;
  if (a == b)
    return 1;
  return mult(fact[a], mult(ifact[b], ifact[a - b]));
}
int inverse(int a) { return modpow(a, MOD - 2); }
void init(int _n) {
  fact.clear();
  ifact.clear();
  inv.clear();
  pow2.clear();
  fact.resize(_n + 1);
  ifact.resize(_n + 1);
  inv.resize(_n + 1);
  pow2.resize(_n + 1);
  pow2[0] = 1;
  ifact[0] = 1;
  fact[0] = 1;
  for (int i = 1; i <= _n; i++) {
    pow2[i] = add(pow2[i - 1], pow2[i - 1]);
    fact[i] = mult(fact[i - 1], i);
    // ifact[i]=mult(ifact[i-1],inv[i]);
  }
  ifact[_n] = inverse(fact[_n]);
  for (int i = _n - 1; i >= 1; i--) {
    ifact[i] = mult(ifact[i + 1], i + 1);
  }
  for (int i = 1; i <= _n; i++) {
    inv[i] = mult(fact[i - 1], ifact[i]);
  }
}

int adj[18][18];
int dp[1700000];
int reach[2][(1 << 16)];
int n, m;
int p3[18];
int cntadj[15000000];

int solve(int u, int bit) {
  if (!(bit & (1 << u)))
    return 0;
  if (reach[u][bit] != -1)
    return reach[u][bit];
  int res = 1;
  vi V;
  for (int i = 0; i < n; i++) {
    if (bit & (1 << i))
      V.pb(i);
  }
  if (bit > 0) {
    for (int j = bit;; j = (bit & (j - 1))) {
      if (j == bit)
        continue;
      int coeff = 1;
      vi VV[2];
      int bb = 0;
      for (int x : V) {
        if (j & (1 << x))
          bb += p3[x]; // VV[1].pb(x);
        else
          bb += p3[x] * 2; // VV[0].pb(x);
      }
      coeff = inverse(pow2[cntadj[bb]]);
      radd(res, MOD - mult(coeff, solve(u, j)));
      if (j == 0)
        break;
    }
  }
  return (reach[u][bit] = res);
}

int V[18];
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  init(1201);
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    adj[u][v] = adj[v][u] = 1;
  }
  p3[0] = 1;
  for (int i = 1; i <= 17; i++)
    p3[i] = p3[i - 1] * 3;
  for (int i = 0; i < 2; i++) {
    memset(reach, -1, sizeof(reach));
    reach[i][(1 << i)] = 1;
  }
  int ans = 0;
  for (int i = 1; i < p3[n]; i++) {
    int cur = i;
    int exv = -1;
    int firstv = -1;
    for (int j = 0; j < n; j++) {
      V[j] = cur % 3;
      cur /= 3;
      if (V[j] != 0) {
        exv = j;
        firstv = V[j];
      }
    }
    cntadj[i] = cntadj[i - firstv * p3[exv]];
    for (int j = 0; j < n; j++) {
      if (V[j] != 0 && V[j] != firstv) {
        cntadj[i] += adj[exv][j];
      }
    }
    /*
    if(!V[1].empty())
    {
            cntadj[i]=cntadj[i-p3[V[1][0]]];
            for(int v:V[2])
            {
                    cntadj[i]+=adj[v][V[1][0]];
            }
    }
    else if(!V[2].empty())
    {
            cntadj[i]=cntadj[i-p3[V[2][0]]*2];
            for(int v:V[1])
            {
                    cntadj[i]+=adj[v][V[2][0]];
            }
    }
    */
    /*
    for(int x:V[1])
    {
            for(int y:V[2])
            {
                    cntadj[i]+=adj[x][y];
            }
    }
    */
    // if(i%100000==0) cerr<<"FINISH "<<i<<' '<<p3[n]<<'\\n';
  }
  // cerr<<"HALFWAY DONE"<<endl;
  for (int i = 0; i < p3[n - 2]; i++) {
    vi V[3];
    V[1].pb(0);
    V[2].pb(1);
    int cur = i;
    int b2 = 0;
    int b1 = 0;
    for (int j = 2; j < n; j++) {
      V[cur % 3].pb(j);
      cur /= 3;
    }
    for (int x : V[1])
      b1 |= (1 << x);
    for (int x : V[2])
      b2 |= (1 << x);
    int pos = 1;
    for (int x : V[1]) {
      for (int y : V[2]) {
        if (adj[x][y]) {
          pos = 0;
          break;
        }
      }
    }
    if (!pos)
      continue;
    int cnt_edge = 0;
    for (int x : V[0]) {
      for (int y : V[1])
        cnt_edge += adj[x][y];
      for (int y : V[2])
        cnt_edge += adj[x][y];
    }
    ans = add(ans, mult(pow2[m - cnt_edge], mult(solve(0, b1), solve(1, b2))));
  }
  ans = add(pow2[m], MOD - ans);
  cout << ans << '\\n';
}