#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class UBigInt;
class BitField;
extern bool primalityTestMillerRabin(const UBigInt& p, const unsigned int& cnt = 100);
class UBigInt {
public:
typedef shared_ptr<BitField> BFPtr;
static UBigInt fromString(const string& str, const unsigned int& base = 10);
UBigInt(const unsigned int& num = 0);
UBigInt(const BFPtr& fld);
UBigInt(const UBigInt& num);
UBigInt operator +(const UBigInt& ade) const;
UBigInt operator -(const UBigInt& sub) const;
UBigInt operator *(const UBigInt& mer) const;
UBigInt operator /(const UBigInt& dsr) const;
UBigInt operator %(const UBigInt& nrm) const;
UBigInt operator <<(const size_t& wid) const;
UBigInt operator >>(const size_t& wid) const;
UBigInt& operator =(const UBigInt& num);
UBigInt& operator +=(const UBigInt& ade);
UBigInt& operator -=(const UBigInt& sub);
UBigInt& operator *=(const UBigInt& mer);
UBigInt& operator /=(const UBigInt& dsr);
UBigInt& operator %=(const UBigInt& nrm);
UBigInt& operator <<=(const unsigned int& wid);
UBigInt& operator >>=(const unsigned int& wid);
UBigInt& operator ++();
UBigInt operator ++(int);
UBigInt& operator --();
UBigInt operator --(int);
bool operator ==(const UBigInt& num) const;
bool operator <(const UBigInt& num) const;
bool operator >(const UBigInt& num) const;
bool operator !=(const UBigInt& num) const;
bool operator <=(const UBigInt& num) const;
bool operator >=(const UBigInt& num) const;
UBigInt power(const UBigInt& exp);
UBigInt modPower(const UBigInt& exp, const UBigInt& nrm);
bool isZero() const;
bool getLSBit() const;
unsigned int getLSInt() const;
string toString(const unsigned int& base = 10) const;
protected:
BFPtr fld;
static BFPtr add(const BFPtr& age, const BFPtr& ade);
static BFPtr subtract(const BFPtr& min, const BFPtr& sub);
static BFPtr multiply(const BFPtr& mca, const BFPtr& mer);
static BFPtr divide(const BFPtr& dde, const BFPtr& dsr, BFPtr* rem = NULL);
static unsigned int charToFigure(const char& ch);
static char figureToChar(const unsigned int& fig);
};
class BitField {
public:
BitField();
BitField(const unsigned int& num);
BitField(const BitField& fld);
virtual ~BitField();
BitField& operator =(const BitField& fld);
bool operator ==(const BitField& fld) const;
bool operator <(const BitField& fld) const;
bool operator >(const BitField& fld) const;
bool operator !=(const BitField& fld) const;
bool operator <=(const BitField& fld) const;
bool operator >=(const BitField& fld) const;
unsigned int getWidth() const;
bool isEmpty() const;
bool isZero() const;
bool getBit(const unsigned int& pos) const;
bool getLSBit() const;
bool getMSBit() const;
unsigned int getLSInt() const;
void setBit(const unsigned int& pos, const bool& bit);
void pushMSBit(const bool& bit);
void pushLSBit(const bool& bit);
void shift(const int& wid);
void trim();
void clear();
string toString() const;
protected:
unsigned char* buf;
unsigned int buf_sz;
int beg;
unsigned int wid;
int compare(const BitField& fld) const;
void extendIfNecessary(const int& wid);
};
#define ASSERT(pred) assert(#pred, pred);
extern void assert(const char* pred_str, const bool& pred);
bool primalityTestMillerRabin(const UBigInt& p, const unsigned int& cnt) {
bool res;
if (p == 1) res = false;
else if (p == 2) res = true;
else if (p.getLSBit() == false) res = false;
else {
UBigInt o = p - 1;
UBigInt q = o;
UBigInt k(1);
while (q.getLSBit() == false) {
q >>= 1;
k++;
}
UBigInt a(2);
UBigInt gap((o - 2) / cnt);
if (gap.isZero()) gap++;
for (; a < p; a += gap) {
UBigInt b = a.modPower(q, p);
if (b != 1 && b != o) {
UBigInt i(1);
for (; i < k; i++) {
b = (b * b) % p;
if (b == 1 || b == o) break;
}
if (i == k) {
res = false;
break;
}
}
}
if (a >= p) res = true;
}
return res;
}
UBigInt UBigInt::fromString(const string& str, const unsigned int& base) {
BFPtr fld(new BitField);
BFPtr base_fld(new BitField(base));
for (string::const_iterator iter = str.begin(); iter != str.end(); iter++) {
if (iter != str.begin()) fld = multiply(fld, base_fld);
unsigned int fig = charToFigure(*iter);
if (fig >= base) throw string("値が範囲を逸脱している。");
fld = add(fld, BFPtr(new BitField(fig)));
}
if (fld->isEmpty()) fld->pushMSBit(true);
return UBigInt(fld);
}
UBigInt::UBigInt(const unsigned int& num) : fld(new BitField(num)) {}
UBigInt::UBigInt(const BFPtr& fld) : fld(fld) {}
UBigInt::UBigInt(const UBigInt& num) : fld(new BitField(*num.fld)) {}
UBigInt UBigInt::operator +(const UBigInt& ade) const {
return UBigInt(add(this->fld, ade.fld));
}
UBigInt UBigInt::operator -(const UBigInt& sub) const {
return UBigInt(subtract(this->fld, sub.fld));
}
UBigInt UBigInt::operator *(const UBigInt& mer) const {
return UBigInt(multiply(this->fld, mer.fld));
}
UBigInt UBigInt::operator /(const UBigInt& dsr) const {
return UBigInt(divide(this->fld, dsr.fld));
}
UBigInt UBigInt::operator %(const UBigInt& nrm) const {
if (nrm.isZero()) throw string("法がゼロ。");
BFPtr rem;
divide(this->fld, nrm.fld, &rem);
return UBigInt(rem);
}
UBigInt UBigInt::operator <<(const unsigned int& wid) const {
BFPtr fld(new BitField(*this->fld));
fld->shift(wid);
return UBigInt(fld);
}
UBigInt UBigInt::operator >>(const unsigned int& wid) const {
BFPtr fld(new BitField(*this->fld));
fld->shift(-wid);
return UBigInt(fld);
}
UBigInt& UBigInt::operator =(const UBigInt& num) {
this->fld = BFPtr(new BitField(*num.fld));
return *this;
}
UBigInt& UBigInt::operator +=(const UBigInt& add) {
return *this = *this + add;
}
UBigInt& UBigInt::operator -=(const UBigInt& sub) {
return *this = *this - sub;
}
UBigInt& UBigInt::operator *=(const UBigInt& mer) {
return *this = *this * mer;
}
UBigInt& UBigInt::operator /=(const UBigInt& dsr) {
return *this = *this / dsr;
}
UBigInt& UBigInt::operator %=(const UBigInt& nrm) {
return *this = *this % nrm;
}
UBigInt& UBigInt::operator <<=(const size_t& wid) {
return *this = *this << wid;
}
UBigInt& UBigInt::operator >>=(const size_t& wid) {
return *this = *this >> wid;
}
UBigInt& UBigInt::operator ++() {
return *this += 1;
}
UBigInt UBigInt::operator ++(int) {
UBigInt res = *this;
*this += 1;
return res;
}
UBigInt& UBigInt::operator --() {
return *this -= 1;
}
UBigInt UBigInt::operator --(int) {
UBigInt res = *this;
*this -= 1;
return res;
}
bool UBigInt::operator ==(const UBigInt& num) const {
return *this->fld == *num.fld;
}
bool UBigInt::operator <(const UBigInt& num) const {
return *this->fld < *num.fld;
}
bool UBigInt::operator >(const UBigInt& num) const {
return *this->fld > *num.fld;
}
bool UBigInt::operator !=(const UBigInt& num) const {
return *this->fld != *num.fld;
}
bool UBigInt::operator <=(const UBigInt& num) const {
return *this->fld <= *num.fld;
}
bool UBigInt::operator >=(const UBigInt& num) const {
return *this->fld >= *num.fld;
}
UBigInt UBigInt::power(const UBigInt& exp) {
if (isZero()) return UBigInt(false);
UBigInt res(true);
UBigInt coef = *this;
for (UBigInt exp2 = exp;;) {
if (exp2.getLSBit()) {
res *= coef;
}
exp2 >>= 1;
if (exp2.isZero()) break;
coef *= coef;
}
return res;
}
UBigInt UBigInt::modPower(const UBigInt& exp, const UBigInt& nrm) {
if (nrm.isZero()) throw string("法がゼロ。");
if (isZero()) return UBigInt(false);
UBigInt res(true);
UBigInt coef = *this % nrm;
for (UBigInt exp2 = exp;;) {
if (exp2.getLSBit()) {
res = (res * coef) % nrm;
}
exp2 >>= 1;
if (exp2.isZero()) break;
coef = (coef * coef) % nrm;
}
return res;
}
bool UBigInt::isZero() const {
return this->fld->isZero();
}
bool UBigInt::getLSBit() const {
return this->fld->getLSBit();
}
unsigned int UBigInt::getLSInt() const {
return this->fld->getLSInt();
}
string UBigInt::toString(const unsigned int& base) const {
string res = "";
BFPtr wrk(new BitField(*this->fld));
BFPtr base_fld(new BitField(base));
while (!wrk->isZero()) {
BFPtr rem;
wrk = divide(wrk, base_fld, &rem);
res += figureToChar(rem->getLSInt());
}
if (res.empty()) res += '0';
reverse(res.begin(), res.end());
size_t pos = 0;
for (; pos < res.length() - 1; pos++) if (res[pos] != '0') break;
return res.substr(pos, res.length() - pos);
}
UBigInt::BFPtr UBigInt::add(const BFPtr& age, const BFPtr& ade) {
BFPtr sum(new BitField);
unsigned int age_pos = 0;
unsigned int ade_pos = 0;
bool carry = false;
while (age_pos < age->getWidth() || ade_pos < ade->getWidth()) {
int age_num = age_pos < age->getWidth() ? (age->getBit(age_pos) == true ? 1 : 0) : 0;
int ade_num = ade_pos < ade->getWidth() ? (ade->getBit(ade_pos) == true ? 1 : 0) : 0;
int sum_num = age_num + ade_num + (carry ? 1 : 0);
carry = sum_num > 1;
if (carry) sum_num -= 2;
sum->pushMSBit(sum_num == 1);
if (age_pos < age->getWidth()) age_pos++;
if (ade_pos < ade->getWidth()) ade_pos++;
}
if (sum->isEmpty()) sum->pushMSBit(false);
if (carry) sum->pushMSBit(true);
return sum;
}
UBigInt::BFPtr UBigInt::subtract(const BFPtr& min, const BFPtr& sub) {
BFPtr dif(new BitField);
unsigned int min_pos = 0;
unsigned int sub_pos = 0;
bool borrow = false;
while (min_pos < min->getWidth() || sub_pos < sub->getWidth()) {
int min_num = min_pos < min->getWidth() ? (min->getBit(min_pos) == true ? 1 : 0) : 0;
int sub_num = sub_pos < sub->getWidth() ? (sub->getBit(sub_pos) == true ? 1 : 0) : 0;
int dif_num = min_num - sub_num - (borrow ? 1 : 0);
borrow = dif_num < 0;
if (borrow) dif_num += 2;
dif->pushMSBit(dif_num == 1);
if (min_pos < min->getWidth()) min_pos++;
if (sub_pos < sub->getWidth()) sub_pos++;
}
if (borrow) throw string("被減数が減数より小さい。");
if (dif->isEmpty()) dif->pushMSBit(false);
dif->trim();
return dif;
}
UBigInt::BFPtr UBigInt::multiply(const BFPtr& mca, const BFPtr& mer) {
BFPtr pro(new BitField(0));
BFPtr wrk(new BitField(*mca));
unsigned int mer_pos = 0;
for (unsigned int mer_pos = 0; mer_pos < mer->getWidth(); mer_pos++) {
if (mer->getBit(mer_pos) == true) pro = add(pro, wrk);
wrk->shift(1);
}
return pro;
}
UBigInt::BFPtr UBigInt::divide(const BFPtr& dde, const BFPtr& dsr, BFPtr* rem) {
if (dsr->isZero()) throw string("除数がゼロ。");
BFPtr quo(new BitField);
BFPtr wnd(new BitField);
for (unsigned int dde_next_pos = dde->getWidth(); dde_next_pos > 0; dde_next_pos--) {
unsigned int dde_pos = dde_next_pos - 1;
wnd->pushLSBit(dde->getBit(dde_pos));
if (*wnd >= *dsr) {
quo->pushLSBit(true);
wnd = subtract(wnd, dsr);
}
else quo->pushLSBit(false);
}
if (quo->isEmpty()) quo->pushMSBit(false);
if (rem) {
*rem = wnd;
if ((*rem)->isEmpty()) (*rem)->pushMSBit(false);
}
return quo;
}
unsigned int UBigInt::charToFigure(const char& ch) {
unsigned int res;
if (ch >= '0' && ch <= '9') res = ch - '0';
else if (ch >= 'A' && ch <= 'Z') res = 10 + ch - 'A';
else if (ch >= 'a' && ch <= 'z') res = 10 + ch - 'a';
else throw string("文字が数ではない。");
return res;
}
char UBigInt::figureToChar(const unsigned int& fig) {
char res;
if (fig >= 0 && fig <= 9) res = '0' + fig;
else if (fig >= 10 && fig <= 36) res = 'A' + (fig - 10);
else throw string("値が範囲を逸脱している。");
return res;
}
BitField::BitField() : buf(nullptr), buf_sz(0), beg(0), wid(0) {}
BitField::BitField(const unsigned int& num) {
this->buf_sz = sizeof(unsigned int);
this->buf = (unsigned char*)malloc(this->buf_sz);
*(unsigned int*)this->buf = num;
this->beg = 0;
this->wid = sizeof(unsigned int) << 3;
trim();
}
BitField::BitField(const BitField& fld) : buf(nullptr), buf_sz(0), beg(0), wid(0) {
if (fld.wid != 0) {
this->buf_sz = fld.buf_sz;
this->buf = (unsigned char*)malloc(this->buf_sz);
memcpy(this->buf, fld.buf, fld.buf_sz);
this->beg = fld.beg;
this->wid = fld.wid;
}
}
BitField::~BitField() {
if (this->buf) free(this->buf);
}
BitField& BitField::operator =(const BitField& fld) {
this->wid = 0;
if (fld.wid != 0) {
this->buf_sz = fld.buf_sz;
this->buf = (unsigned char*)malloc(this->buf_sz);
memcpy(this->buf, fld.buf, fld.buf_sz);
this->beg = fld.beg;
this->wid = fld.wid;
}
return *this;
}
bool BitField::operator ==(const BitField& fld) const {
return compare(fld) == 0;
}
bool BitField::operator <(const BitField& fld) const {
return compare(fld) < 0;
}
bool BitField::operator >(const BitField& fld) const {
return compare(fld) > 0;
}
bool BitField::operator !=(const BitField& fld) const {
return compare(fld) != 0;
}
bool BitField::operator <=(const BitField& fld) const {
return compare(fld) <= 0;
}
bool BitField::operator >=(const BitField& fld) const {
return compare(fld) >= 0;
}
unsigned int BitField::getWidth() const {
return this->wid;
}
bool BitField::isEmpty() const {
return this->wid == 0;
}
bool BitField::isZero() const {
bool res = true;
for (unsigned int pos = 0; pos < this->wid; pos++) {
if (getBit(pos) == true) {
res = false;
break;
}
}
return res;
}
bool BitField::getBit(const unsigned int& pos) const {
unsigned int abs_pos = this->beg + pos;
unsigned int buf_wid = this->buf_sz << 3;
if (abs_pos >= buf_wid) abs_pos -= buf_wid;
return ((this->buf[abs_pos >> 3] >> (abs_pos & 0x7)) & 1) == 1;
}
bool BitField::getLSBit() const {
return getBit(0);
}
bool BitField::getMSBit() const {
return getBit(this->wid - 1);
}
unsigned int BitField::getLSInt() const {
unsigned int res = 0;
unsigned int int_wid = sizeof(unsigned int) << 3;
for (unsigned int pos = 0; pos < int_wid && pos < this->wid; pos++)
res |= (getBit(pos) == true ? 1 : 0) << pos;
return res;
}
void BitField::setBit(const unsigned int& pos, const bool& bit) {
unsigned int abs_pos = this->beg + pos;
unsigned int buf_wid = this->buf_sz << 3;
if (abs_pos >= buf_wid) abs_pos -= buf_wid;
if (bit) this->buf[abs_pos >> 3] |= 1 << (abs_pos & 0x7);
else this->buf[abs_pos >> 3] &= ~(1 << (abs_pos & 0x7));
}
void BitField::pushMSBit(const bool& bit) {
extendIfNecessary(1);
setBit(this->wid - 1, bit);
}
void BitField::pushLSBit(const bool& bit) {
extendIfNecessary(-1);
setBit(0, bit);
}
void BitField::shift(const int& wid) {
if (wid < 0) {
this->beg -= wid;
unsigned int buf_wid = this->buf_sz << 3;
if (this->beg >= buf_wid) this->beg -= buf_wid;
this->wid += wid;
}
else {
extendIfNecessary(-wid);
for (unsigned int pos = 0; pos < wid; pos++)
setBit(pos, false);
}
}
void BitField::trim() {
while (this->wid != 0 && getMSBit() == false) this->wid--;
}
void BitField::clear() {
this->wid = 0;
}
string BitField::toString() const {
string res = "";
for (unsigned int pos = 0; pos < this->wid; pos++)
res += getBit(pos) == true ? '1' : '0';
return res;
}
int BitField::compare(const BitField& fld) const {
int res = 0;
for (unsigned int next_pos = this->wid < fld.wid ? fld.wid : this->wid; next_pos > 0; next_pos--) {
unsigned int pos = next_pos - 1;
bool bit1 = pos < this->wid ? getBit(pos) : false;
bool bit2 = pos < fld.wid ? fld.getBit(pos) : false;
if (bit1 == false && bit2 == true) {
res = -1;
break;
}
else if (bit1 == true && bit2 == false) {
res = 1;
break;
}
}
return res;
}
void BitField::extendIfNecessary(const int& wid) {
unsigned int abs_wid = wid < 0 ? -wid : wid;
unsigned int need_sz = (this->wid + abs_wid + 7) >> 3;
if (need_sz > this->buf_sz) {
unsigned int new_buf_sz = need_sz << 1;
unsigned char* new_buf = (unsigned char*)malloc(new_buf_sz);
unsigned int new_beg = 0;
if (this->wid != 0) {
unsigned int fld_beg = this->beg >> 3;
unsigned int fld_end = (this->beg + this->wid + 7) >> 3;
if (fld_end <= this->buf_sz) {
unsigned int fld_sz = fld_end - fld_beg;
memcpy(new_buf + fld_beg, this->buf + fld_beg, fld_sz);
new_beg = this->beg;
}
else {
unsigned int low_sz = this->buf_sz - fld_beg;
unsigned int new_low_beg = new_buf_sz - low_sz;
memcpy(new_buf + new_low_beg, this->buf + fld_beg, low_sz);
unsigned int high_sz = fld_end - this->buf_sz;
memcpy(new_buf, this->buf, high_sz);
unsigned int buf_wid = this->buf_sz << 3;
unsigned int low_wid = buf_wid - this->beg;
unsigned int new_buf_wid = new_buf_sz << 3;
new_beg = new_buf_wid - low_wid;
}
free(this->buf);
}
this->buf_sz = new_buf_sz;
this->buf = new_buf;
this->beg = new_beg;
}
if (wid < 0) {
this->beg += wid;
int buf_wid = this->buf_sz << 3;
if (this->beg < 0) this->beg += buf_wid;
}
this->wid += abs_wid;
}
void assert(const char* pred_str, const bool& pred) {
if (pred) {
cout << "アサート成功: " << pred_str << endl;
}
else {
cerr << "アサート失敗: " << pred_str << endl;
exit(1);
}
}
int main() {
try {
clock_t begin = clock();
ASSERT(primalityTestMillerRabin(UBigInt::fromString("0")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("1")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("2")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("3")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("4")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("5")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("6")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("7")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("8")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("9")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("87")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("89")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("329")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("331")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("561")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("563")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("807")) == false)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("809")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("2251")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("59561")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("181243")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("14414443")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("10461401779")) == true)
ASSERT(primalityTestMillerRabin(UBigInt::fromString("1853028778786433")) == true)
clock_t end = clock();
clock_t elapsed = end - begin;
cout << (elapsed / CLOCKS_PER_SEC) << "." << setfill('0') << setw(3) << ((elapsed % CLOCKS_PER_SEC) * 1000 / CLOCKS_PER_SEC) << " secs" << endl;
}
catch (const string& msg) {
cerr << msg << endl;
return 1;
}
return 0;
}