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

string to_string(string s) { return '"' + s + '"'; }
string to_string(bool b) { return b ? "true" : "false"; }
template <class T, class U> string to_string(pair<T, U> p);
template <class C> string to_string(C c) {
  string res = "{";
  for (auto e : c) res += to_string(e) + ", ";
  return res += "}";
}
template <size_t N> string to_string(bitset<N> bs) {
  string res;
  for (size_t i = 0; i < N; ++i) res += '0' + bs[i];
  return res;
}
template <class T, class U> string to_string(pair<T, U> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}

void debug() { cerr << '\n'; }
template <class Head, class... Tail> void debug(Head head, Tail... tail) {
  cerr << ' ' << to_string(head), debug(tail...);
}
#ifdef LOCAL
#define DEBUG(...) cerr << "[" << #__VA_ARGS__ << "]:", debug(__VA_ARGS__)
#else
#define DEBUG(...)
#endif

long long tmod(long long a, long long mod) {
  return (a %= mod) < 0 ? a + mod : a;
}
long long tdiv(long long a, long long b) { 
  return (a - tmod(a, b)) / b;
}

// Description: 区間をsetで管理するデータ構造(なお実装はmap)．各クエリO(log区間数)．
 
// #### attention! : [l, r] ( include r, not [l, r) )
class SegmentMap : public std::map<long long, long long> {
private:
    bool flagToMergeAdjacentSegment;
public:
    // if merge [l, c] and [c+1, r], set flagToMergeAdjacentSegment to true
    SegmentMap(bool flagToMergeAdjacentSegment) :
        flagToMergeAdjacentSegment(flagToMergeAdjacentSegment) {}
    // __exist -> iterator pair(l, r) (contain p)
    // noexist -> map.end()
    auto get(long long p) const {
        auto it = upper_bound(p);
        if (it == begin() || (--it)->second < p) return end();
        return it;
    }
    // insert segment [l, r]
    void insert(long long l, long long r) {
        auto itl = upper_bound(l), itr = upper_bound(r + flagToMergeAdjacentSegment);
        if (itl != begin()) {
            if ((--itl)->second < l - flagToMergeAdjacentSegment) ++itl;
        }
        if (itl != itr) {
            l = std::min(l, itl->first);
            r = std::max(r, std::prev(itr)->second);
            erase(itl, itr);
        }
        (*this)[l] = r;
    }
    // remove segment [l, r]
    void remove(long long l, long long r) {
        auto itl = upper_bound(l), itr = upper_bound(r);
        if (itl != begin()) {
            if ((--itl)->second < l) ++itl;
        }
        if (itl == itr) return;
        int tl = std::min(l, itl->first), tr = std::max(r, std::prev(itr)->second);
        erase(itl, itr);
        if (tl < l) (*this)[tl] = l - 1;
        if (r < tr) (*this)[r + 1] = tr;
    }
    // Is p and q in same segment?
    bool same(long long p, long long q) const {
        const auto&& it = get(p);
        return it != end() && it->first <= q && q <= it->second;
    }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  long long n, a, d;
  cin >> n >> a >> d;
  if (d == 0) {
    if (a == 0) {
      cout << 1 << '\n';
    } else {
      cout << n + 1 << '\n';
    }
    return 0;
  } else if (d < 0) {
    a += (n - 1) * d;
    d = -d;
  }
  map< long long, vector<long long> > mp;
  for (int k = 0; k <= n; ++k) {
    mp[tmod(a * k, d)].push_back(k);
  }
  long long res = 0;
  for (auto e : mp) {
    SegmentMap smp(true);
    for (long long k : e.second) {
      long long l = tdiv(a * k, d) + k * (k - 1) / 2;
      long long u = tdiv(a * k, d) + k * (n - k + n - 1) / 2;
      smp.insert(l, u);
    }
    DEBUG(smp);
    for (auto e : smp) {
      res += e.second - e.first + 1;
    }
  }
  cout << res << '\n';
}


Measured memory_bytes: 22144