QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#290466#6186. Cryptography Problemucup-team087#AC ✓255ms3932kbC++147.2kb2023-12-25 01:47:032023-12-25 01:47:03

Judging History

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

  • [2023-12-25 01:47:03]
  • 评测
  • 测评结果:AC
  • 用时:255ms
  • 内存:3932kb
  • [2023-12-25 01:47:03]
  • 提交

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; }

////////////////////////////////////////////////////////////////////////////////
struct ModLong {
  static unsigned long long M;
  static long double INV_M;
  static void setM(unsigned long long m) { M = m; INV_M = 1.0L / M; }
  unsigned long long x;
  ModLong() : x(0ULL) {}
  ModLong(unsigned x_) : x(x_ % M) {}
  ModLong(unsigned long long x_) : x(x_ % M) {}
  ModLong(int x_) : x(((x_ %= static_cast<long long>(M)) < 0) ? (x_ + static_cast<long long>(M)) : x_) {}
  ModLong(long long x_) : x(((x_ %= static_cast<long long>(M)) < 0) ? (x_ + static_cast<long long>(M)) : x_) {}
  ModLong &operator+=(const ModLong &a) { x = ((x += a.x) >= M) ? (x - M) : x; return *this; }
  ModLong &operator-=(const ModLong &a) { x = ((x -= a.x) >= M) ? (x + M) : x; return *this; }
  ModLong &operator*=(const ModLong &a) {
    // https://github.com/kth-competitive-programming/kactl/blob/main/doc/modmul-proof.pdf
    // This works at least for M < 2^62, assuming the usual 80-bit long double.
    const long long y = x * a.x - M * static_cast<unsigned long long>(INV_M * x * a.x);
    x = (y < 0LL) ? (y + M) : (y >= static_cast<long long>(M)) ? (y - M) : y;
    return *this;
  }
  ModLong &operator/=(const ModLong &a) { return (*this *= a.inv()); }
  ModLong pow(long long e) const {
    if (e < 0) return inv().pow(-e);
    ModLong a = *this, b = 1ULL; for (; e; e >>= 1) { if (e & 1) b *= a; a *= a; } return b;
  }
  ModLong inv() const {
    unsigned long long a = M, b = x; long long y = 0, z = 1;
    for (; b; ) { const unsigned long long q = a / b; const unsigned long long c = a - q * b; a = b; b = c; const long long w = y - static_cast<long long>(q) * z; y = z; z = w; }
    assert(a == 1ULL); return ModLong(y);
  }
  ModLong operator+() const { return *this; }
  ModLong operator-() const { ModLong a; a.x = x ? (M - x) : 0ULL; return a; }
  ModLong operator+(const ModLong &a) const { return (ModLong(*this) += a); }
  ModLong operator-(const ModLong &a) const { return (ModLong(*this) -= a); }
  ModLong operator*(const ModLong &a) const { return (ModLong(*this) *= a); }
  ModLong operator/(const ModLong &a) const { return (ModLong(*this) /= a); }
  template <class T> friend ModLong operator+(T a, const ModLong &b) { return (ModLong(a) += b); }
  template <class T> friend ModLong operator-(T a, const ModLong &b) { return (ModLong(a) -= b); }
  template <class T> friend ModLong operator*(T a, const ModLong &b) { return (ModLong(a) *= b); }
  template <class T> friend ModLong operator/(T a, const ModLong &b) { return (ModLong(a) /= b); }
  explicit operator bool() const { return x; }
  bool operator==(const ModLong &a) const { return (x == a.x); }
  bool operator!=(const ModLong &a) const { return (x != a.x); }
  friend std::ostream &operator<<(std::ostream &os, const ModLong &a) { return os << a.x; }
};
unsigned long long ModLong::M;
long double ModLong::INV_M;
////////////////////////////////////////////////////////////////////////////////

using Mint = ModLong;


using INT = __int128;

INT divFloor(INT a, INT b) {
  return a / b - (((a ^ b) < 0 && a % b != 0) ? 1 : 0);
}
INT divCeil(INT a, INT b) {
  return a / b + (((a ^ b) > 0 && a % b != 0) ? 1 : 0);
}


constexpr int H = 6;
constexpr int NUM_CANDS = 100;
constexpr int WIDTH = 10;

int M;
Int P;
vector<Mint> A, C;
Int maxErr;

bool check(Mint x) {
  for (int i = 0; i < M; ++i) {
    const Mint e = C[i] - A[i] * x;
    if (!((Int)e.x <= maxErr || P - maxErr <= (Int)e.x)) {
      return false;
    }
  }
  return true;
}

int main() {
  for (int numCases; ~scanf("%d", &numCases); ) { for (int caseId = 1; caseId <= numCases; ++caseId) {
    scanf("%d%lld", &M, &P);
    Mint::setM(P);
    A.resize(M);
    C.resize(M);
    for (int i = 0; i < M; ++i) {
      scanf("%llu%llu", &A[i].x, &C[i].x);
    }
    
    maxErr = P / 200;
    
    // A[0] x + y = C[0]  (mod P)
    const Mint invA0 = A[0].inv();
    
    vector<pair<Mint, Mint>> acss[H + 1];
    for (int i = 1; i < M; ++i) {
      acss[0].emplace_back(-invA0 * A[i], C[i] - invA0 * A[i] * C[0]);
    }
    for (int h = 0; ; ++h) {
      sort(acss[h].begin(), acss[h].end(), [&](const pair<Mint, Mint> &ac0, const pair<Mint, Mint> &ac1) -> bool {
        return (ac0.first.x < ac1.first.x);
      });
      acss[h].erase(unique(acss[h].begin(), acss[h].end()), acss[h].end());
      if ((int)acss[h].size() > NUM_CANDS) {
        acss[h].resize(NUM_CANDS);
      }
// cerr<<"acss["<<h<<"] = ";for(int i=0;i<10;++i)cerr<<acss[h][i]<<" ";cerr<<"..."<<endl;
      if (h == H) {
        break;
      }
      for (int i = 0; i < (int)acss[h].size(); ++i) {
        for (int j = i + 1; j < (int)acss[h].size() && j < i + WIDTH; ++j) {
          const Mint ai = acss[h][i].first;
          const Mint ci = acss[h][i].second;
          const Mint aj = acss[h][j].first;
          const Mint cj = acss[h][j].second;
          if (ai != aj) {
            acss[h + 1].emplace_back(aj - ai, cj - ci);
          }
        }
      }
    }
    
    // possible intervals for y
    vector<pair<Int, Int>> fs;
    fs.emplace_back(-maxErr, +maxErr);
    
    for (int h = H; h >= 0; --h) {
      const INT err = maxErr << h;
      for (const auto &ac : acss[h]) {
        const INT a = ac.first.x;
        const INT c = ac.second.x;
        vector<pair<Int, Int>> gs;
        for (const auto &f : fs) {
          const INT lb = a * f.first - err;
          const INT ub = a * f.second + err;
          for (INT cc = c + P * divCeil(lb - c, P); cc <= ub; cc += P) {
            Int mn = divCeil(cc - err, a);
            Int mx = divFloor(cc + err, a);
            chmax(mn, f.first);
            chmin(mx, f.second);
            if (mn <= mx) {
              gs.emplace_back(mn, mx);
            }
          }
        }
        fs.swap(gs);
      }
// cerr<<"fs = "<<fs<<endl;
    }
    
    assert((int)fs.size() == 1);
    assert(fs[0].first == fs[0].second);
    const Mint y = fs[0].first;
    const Mint x = invA0 * (C[0] - y);
    assert(check(x));
    printf("%llu\n", x.x);
  }
#ifndef LOCAL
  break;
#endif
  }
  return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3800kb

input:

1
50 922033901407246477
492300877907148697 8585039545574817
36478175140515505 237143454432095134
537753813197233578 694568987600933631
82789600405017625 562554784008054548
282428338659751664 111810756866364131
822189940492446170 74373256662670811
772047021157436862 845822103589054835
905076737759700...

output:

578607642570710976

result:

ok 1 number(s): "578607642570710976"

Test #2:

score: 0
Accepted
time: 24ms
memory: 3916kb

input:

50
50 927676989640655977
762098094289388675 554350133173402673
220848340400099833 10383368447694956
193839768013701504 379314325246244053
469365359426047896 616262947838432737
678500220535707545 834311280111269471
167419353273448183 166399514139956977
328321928151136515 281838830155886019
7710446445...

output:

254386793227895013
503373249026109683
617255058572731111
468676128207905624
504667964722475709
706980297728347748
654692631554025788
717119724503084980
48846540328002409
457755605535919837
731004188713847898
881500317550344403
265866468225776627
700114442334748277
772736562662367547
4770957264032135...

result:

ok 50 numbers

Test #3:

score: 0
Accepted
time: 255ms
memory: 3920kb

input:

500
50 951821513919240751
781258612744948669 555654292257394605
413029409925362472 528677554280211238
642254341504063583 252890250480181779
77913229002142898 852299116162342377
163586964773590385 301627013265727254
125813686708831709 851092599442448537
81859193591161149 292739685639200100
8004099527...

output:

322665687973068008
719744704337683378
223621712975394904
578842113669482761
579478401273129423
894615012983560279
55304797288242586
900547069473317102
841180533649876743
254296854628506468
165788977022011896
452665978765620390
893182474374282887
888765525028652186
165384334567641643
3096260905621286...

result:

ok 500 numbers

Test #4:

score: 0
Accepted
time: 251ms
memory: 3868kb

input:

500
50 918826966998423649
530004725701494083 461211593687456594
63103588668618552 819676939043626802
845224244943758942 735446711222510978
569183338186454323 884938560895198255
369490838717379648 333643655158879597
799092903635804915 458323668175155716
596200969807461760 751602048149560036
137459688...

output:

356039301456951045
735071103390342669
907633045757956007
80333220403160355
512654676652610218
853151271051375985
6900635554229793
319250522861749251
502089686656976731
706400239469090662
864293875669636701
184585628877202200
765153323638554684
402732305683171984
96578015632385890
33355119284189045
3...

result:

ok 500 numbers

Test #5:

score: 0
Accepted
time: 255ms
memory: 3932kb

input:

500
50 974253393840009889
594332492408784824 973795908768118711
374921723194021568 146694632264962823
158991793399209625 630100905073861940
386845674820240430 546167425238254176
583567998099720927 555458291915934761
662461153156085006 118223913225418273
170565109472431590 707652557260570730
77396204...

output:

721648842958392017
132349150866295563
932229954637440499
683889607900407446
691629840948421027
33025736080549009
495041676223202172
647589505742632734
186935292562953038
110626757212384825
685749428568030610
519425761135381806
758834050890676812
828787588813279594
232938032671135667
4540525995638170...

result:

ok 500 numbers