QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#120141#6188. Elliptic Curve Problemhos_lyricAC ✓2126ms5880kbC++146.6kb2023-07-06 14:12:522023-07-06 14:13:02

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-07-06 14:13:02]
  • 评测
  • 测评结果:AC
  • 用时:2126ms
  • 内存:5880kb
  • [2023-07-06 14:12:52]
  • 提交

answer

#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using namespace std;

using Int = long long;

template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; }
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }

#ifndef LIBRA_OTHER_INT128_H_
#define LIBRA_OTHER_INT128_H_

#include <stdio.h>
#include <iostream>

constexpr unsigned __int128 toUInt128(const char *s) {
  unsigned __int128 x = 0;
  for (; *s; ++s) x = x * 10 + (*s - '0');
  return x;
}
constexpr __int128 toInt128(const char *s) {
  if (*s == '-') return -toInt128(s + 1);
  __int128 x = 0;
  for (; *s; ++s) x = x * 10 + (*s - '0');
  return x;
}
unsigned __int128 inUInt128() {
  static char buf[41];
  scanf("%s", buf);
  return toUInt128(buf);
}
__int128 inInt128() {
  static char buf[41];
  scanf("%s", buf);
  return toInt128(buf);
}

void out(unsigned __int128 x) {
  static char buf[41];
  int len = 0;
  do { buf[len++] = '0' + static_cast<int>(x % 10); } while (x /= 10);
  for (int i = len; --i >= 0; ) putchar(buf[i]);
}
void out(__int128 x) {
  if (x < 0) {
    putchar('-');
    out(-static_cast<unsigned __int128>(x));
  } else {
    out(static_cast<unsigned __int128>(x));
  }
}
std::ostream &operator<<(std::ostream &os, unsigned __int128 x) {
  static char buf[41];
  int len = 0;
  do { buf[len++] = '0' + static_cast<int>(x % 10); } while (x /= 10);
  for (int i = len; --i >= 0; ) os << buf[i];
  return os;
}
std::ostream &operator<<(std::ostream &os, __int128 x) {
  if (x < 0) {
    os << '-' << -static_cast<unsigned __int128>(x);
  } else {
    os << static_cast<unsigned __int128>(x);
  }
  return os;
}

#endif  // LIBRA_OTHER_INT128_H_


using INT = __int128;

/*
  -(a, b): out
  -(c, d): in
*/
struct Info {
  INT a, b, c, d;
};
Info stack[1'000'010];

// \sum[0<x<=(P-1)/2] floor((x^2 + A) / P)
INT solve(INT P, INT A) {
// cerr<<"solve "<<P<<" "<<A<<endl;
  // above
  auto inside = [&](INT x, INT y) -> bool {
    return (x >= 0 && P * y > x * x + A);
  };
  
  // max k s.t. (x - k u, y - k v): in
  auto maxIn = [&](INT x, INT y, INT u, INT v) -> INT {
    assert(inside(x, y));
    if (u == 0) {
      assert(v == 1);
      return y - ((x * x + A) / P) - 1;
    }
    // in, out
    auto check = [&](INT k) -> bool {
      return inside(x - k * u, y - k * v);
    };
    INT lo = 0, hi = 1;
    for (; check(hi); ) {
      lo = hi;
      hi <<= 1;
    }
    for (; lo + 1 < hi; ) {
      const INT mid = (lo + hi) / 2;
      (check(mid) ? lo : hi) = mid;
    }
    return lo;
  };
  
  INT x = (P - 1) / 2;
  INT y = (x*x + A) / P + 1;
  
  int top = 0;
  stack[top] = Info{0, 1, 1, 0};
  
  INT ans = 0;
  for (; x > 0; ) {
// cerr<<"x = "<<x<<", y = "<<y<<endl;
    bool side;
    for (; ; ) {
      const auto &f = stack[top];
// cerr<<"  f = ("<<f.a<<", "<<f.b<<") ("<<f.c<<", "<<f.d<<")"<<endl;
      if (!inside(x - f.a, y - f.b) && inside(x - f.c, y - f.d)) {
        side = inside(x - (f.a + f.c), y - (f.b + f.d));
        break;
      } else {
        --top;
      }
    }
    for (; ; side = !side) {
      const auto &f = stack[top];
// cerr<<"  f = "<<f.a<<" "<<f.b<<" "<<f.c<<" "<<f.d<<", side = "<<side<<endl;
      if (side) {
        const INT k = maxIn(x - f.c, y - f.d, f.a, f.b);
        stack[++top] = Info{f.a, f.b, k * f.a + f.c, k * f.b + f.d};
      } else {
        /*
          P (y - (b + k d)) > (x - (a + k c))^2 + A
          c^2 k^2 - (2 (x - a) c - P d) k + * < 0
        */
        const INT numer = 2 * (x - f.a) * f.c - P * f.d;
        const INT denom = 2 * f.c * f.c;
// cerr<<"    jiku = "<<numer<<"/"<<denom<<endl;
        INT q = numer / denom, r = numer % denom;
        if (r < 0) {
          --q;
          r += denom;
        }
        if (2 * r > denom) {
          ++q;
          r -= denom;
        }
        auto check = [&](INT k) -> bool {
          const INT xx = x - (f.a + k * f.c);
          const INT yy = y - (f.b + k * f.d);
          return inside(xx, yy);
        };
        // out, in
        INT lo = 1, hi = min(q, (x - f.a) / f.c);
// cerr<<"    q = "<<q<<", hi = "<<hi<<", check(hi) = "<<check(hi)<<endl;
        if (check(hi)) {
          const INT lim = hi;
          hi = 2;
          for (; !check(hi); ) {
            lo = hi;
            hi <<= 1;
            if (hi >= lim) {
              hi = lim;
              break;
            }
          }
          for (; lo + 1 < hi; ) {
            const INT mid = (lo + hi) / 2;
            (check(mid) ? hi : lo) = mid;
          }
          const INT k = lo;
          stack[++top] = Info{f.a + k * f.c, f.b + k * f.d, f.c, f.d};
        } else {
          // convex hull slope
          const INT u = f.c, v = f.d;
          const INT k = maxIn(x, y, u, v);
          const INT xx = x - k * u;
          const INT yy = y - k * v;
// cerr<<"    (u, v) = ("<<u<<", "<<v<<"), k = "<<k<<endl;
          ans += ((x - xx + 1) * (y + yy + 1) - (k + 1)) / 2 - (x - xx + 1) - (yy - 1);
          x = xx;
          y = yy;
          break;
        }
      }
    }
  }
  return ans;
}


void stress() {
  for (INT P = 3; P < 1000; P += 2) {
    for (INT A = 0; A <= P; ++A) {
      INT brt = 0;
      for (INT x = 1; x <= (P - 1) / 2; ++x) {
        brt += (x*x + A) / P;
      }
      const INT res = solve(P, A);
      if (brt != res) {
        cerr << P << " " << A << ": " << brt << " " << res << endl;
        assert(false);
      }
    }
  }
}

int main() {
  // stress();
  
  Int P, L, R;
  for (; ~scanf("%lld%lld%lld", &P, &L, &R); ) {
    INT ans = 0;
    ans += solve(P, P - L);
    ans -= solve(P, P - R - 1);
    cout << ans << endl;
  }
  return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 3584kb

input:

11 3 8

output:

3

result:

ok 1 number(s): "3"

Test #2:

score: 0
Accepted
time: 100ms
memory: 3660kb

input:

998244353 11451400 919810000

output:

454174074

result:

ok 1 number(s): "454174074"

Test #3:

score: 0
Accepted
time: 2079ms
memory: 3796kb

input:

96311898227 25437319919 55129361817

output:

14846091352

result:

ok 1 number(s): "14846091352"

Test #4:

score: 0
Accepted
time: 2032ms
memory: 3780kb

input:

93361455259 23166562299 23393760915

output:

113606479

result:

ok 1 number(s): "113606479"

Test #5:

score: 0
Accepted
time: 2060ms
memory: 3864kb

input:

95670332497 15858139735 18812394512

output:

1477133816

result:

ok 1 number(s): "1477133816"

Test #6:

score: 0
Accepted
time: 2058ms
memory: 3844kb

input:

94221254297 78612110347 90331192055

output:

5859602618

result:

ok 1 number(s): "5859602618"

Test #7:

score: 0
Accepted
time: 2022ms
memory: 3940kb

input:

92756073587 18915851957 32881684894

output:

6982950261

result:

ok 1 number(s): "6982950261"

Test #8:

score: 0
Accepted
time: 2032ms
memory: 5880kb

input:

93651628361 3508055978 32362767220

output:

14427310592

result:

ok 1 number(s): "14427310592"

Test #9:

score: 0
Accepted
time: 2090ms
memory: 3836kb

input:

97506758381 48269906857 58513759044

output:

5121898347

result:

ok 1 number(s): "5121898347"

Test #10:

score: 0
Accepted
time: 2125ms
memory: 3816kb

input:

99954950231 20710324571 44996152988

output:

12142951150

result:

ok 1 number(s): "12142951150"

Test #11:

score: 0
Accepted
time: 2118ms
memory: 3836kb

input:

99367158071 38747300608 85189731653

output:

23221174712

result:

ok 1 number(s): "23221174712"

Test #12:

score: 0
Accepted
time: 2126ms
memory: 3792kb

input:

99936206351 6721710119 93710740278

output:

43494512281

result:

ok 1 number(s): "43494512281"