結果
| 問題 |
No.187 中華風 (Hard)
|
| コンテスト | |
| ユーザー |
東前頭十一枚目
|
| 提出日時 | 2019-09-29 01:39:44 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 352 ms / 3,000 ms |
| コード長 | 3,180 bytes |
| コンパイル時間 | 1,556 ms |
| コンパイル使用メモリ | 170,584 KB |
| 実行使用メモリ | 6,820 KB |
| 最終ジャッジ日時 | 2024-10-03 04:22:15 |
| 合計ジャッジ時間 | 6,516 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 25 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
namespace ChineseRemainderTheorem {
template<typename T>
inline T modulo(T x, const T MOD) {
if(0 <= x and x < MOD) return x;
x %= MOD;
if(x < 0) x += MOD;
return x;
}
// gcd(a, b)
// ap + bq = gcd(a, b)を満たす(p, q)
template<typename T>
T exGCD(T a, T b, T &p, T &q) {
if(b == 0) {
// gcd(a, b)p + 0q = gcd(a, b)
p = 1, q = 0;
return a;
}
T ret = exGCD(b, a % b, q, p);
q -= a / b * p;
return ret;
}
// gcd(a, b)
template<typename T>
T exGCD(T a, T b) {
T _p, _q;
return exGCD(a, b, _p, _q);
}
// Garnerの前処理(互いに素にする)
// lcm(mod) % MOD
template<typename T>
T normalisation(vector<T> &b, vector<T> &mod, const T MOD = numeric_limits<T>::max()) {
for(int i = 0; i < (int)b.size(); ++i) {
for(int j = 0; j < i; ++j) {
T g = exGCD(mod[i], mod[j]);
// 必要十分性の確認
if ((b[i] - b[j]) % g != 0) throw "NOT FOUND";
mod[i] /= g;
mod[j] /= g;
T gi = exGCD(mod[i], g);
T gj = g / gi;
// 共通する場合,iの方が指数大
while(true) {
T gg = exGCD(gi, gj);
if(gg == 1) break;
gi *= gg, gj /= gg;
}
mod[i] *= gi;
mod[j] *= gj;
b[i] = modulo(b[i], mod[i]);
b[j] = modulo(b[j], mod[j]);
}
}
T ret = 1;
for(int i = 0; i < (int)b.size(); ++i) {
ret *= mod[i];
ret = modulo(ret, MOD);
}
return ret;
}
// x ≡ b(mod m)を満たすx(mod M (= lcm m))
template<typename T>
T CRT(vector<T> &b, vector<T> &mod) {
// x ≡ 0(mod 1)は全ての整数
T x = 0, MOD = 1;
for(int i = 0; i < (int)b.size(); ++i) {
T p, _q;
T d = exGCD(MOD, mod[i], p, _q);
// 必要十分性の確認
if((x - b[i]) % d != 0) throw "NOT FOUND";
// nextMOD = MOD * (mod[i] / d)なので部分的にmodが取れてオーバーフロー回避
x = x - modulo((x - b[i]) / d * p, (mod[i] / d)) * MOD;
// lcm(M, m) = M * m / gcd(M, m)
MOD = MOD * (mod[i] / d);
x = modulo(x, MOD);
}
return modulo(x, MOD);
}
template<typename T>
T Garner(vector<T> &b, vector<T> &mod, T MOD = numeric_limits<T>::max()) {
try {
normalisation(b, mod, MOD);
}
catch(...) {
throw "NOT FOUND";
}
vector<T> p(b.size());
for(int i = 0; i < (int)b.size(); ++i) {
p[i] = b[i] % mod[i];
for(int j = 0; j < i; ++j) {
T inv, _tmp;
exGCD(mod[j], mod[i], inv, _tmp);
inv = modulo(inv, mod[i]);
p[i] = (p[i] - p[j]) * inv;
p[i] = modulo(p[i], mod[i]);
}
}
// 復元
T ret = 0;
for(int i = 0; i < (int)b.size(); ++i) {
T tmp = modulo(p[i], MOD);
for(int j = 0; j < i; ++j) {
tmp *= mod[j];
tmp = modulo(tmp, MOD);
}
ret += tmp;
ret = modulo(ret, MOD);
}
return ret;
}
};
int main() {
using namespace ChineseRemainderTheorem;
const int64_t MOD = 1e9 + 7;
int n; cin >> n;
vector<int64_t> x(n), y(n);
bool zero = true;
for(int i = 0; i < n; ++i) {
cin >> x[i] >> y[i];
if(x[i] > 0) zero = false;
}
if(zero) {
cout << normalisation(x, y, MOD) << '\n';
return 0;
}
try {
int64_t ans = Garner(x, y, MOD);
cout << ans << '\n';
}
catch(...) {
cout << -1 << '\n';
}
return 0;
}
東前頭十一枚目