#pragma warning (disable: 4786)
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<deque>
#include<map>
#include<algorithm>
using namespace std;
#ifdef _WIN32
typedef unsigned __int64 UINT64;
#elif
typedef unsigned long long UINT64;
#endif
//1000以内素数表
UINT64 gPrimeTable1000[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,
211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,
337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,
461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,
601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,
739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,
881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997};
/******************************************************************************
数论类
******************************************************************************/
class Number
{
public:
Number(UINT64 n=0) : num(n) {} //构造函数
void print (ostream& oo) const; //打印
static Number rand(); //随机数
//基本运算
bool operator == (const Number& n) const {return num == n.num;}
bool operator != (const Number& n) const {return num != n.num;}
bool operator > (const Number& n) const {return num > n.num;}
bool operator < (const Number& n) const {return num < n.num;}
bool operator >= (const Number& n) const {return num >= n.num;}
bool operator <= (const Number& n) const {return num <= n.num;}
Number operator + (const Number& n) const {return num + n.num;}
Number operator - (const Number& n) const {return num - n.num;}
Number operator * (const Number& n) const {return num * n.num;}
Number operator / (const Number& n) const {return num / n.num;}
Number operator % (const Number& n) const {return num % n.num;}
Number& operator += (const Number& n) {num += n.num; return *this;}
Number& operator -= (const Number& n) {num -= n.num; return *this;}
Number& operator *= (const Number& n) {num *= n.num; return *this;}
Number& operator /= (const Number& n) {num /= n.num; return *this;}
Number& operator %= (const Number& n) {num %= n.num; return *this;}
bool isPrime() const; //是否素数
Number power(unsigned int index) const; //幂
Number powerModule(Number index, Number mod) const; //幂余
void factorization(map<Number,int>& factor) const; //因子分解
Number primeNumber(Number n) const; //n以内素数个数
Number eulerFunc() const; //Euler函数φ
Number mobiusFunc() const; //M?bius函数μ
int legendre(Number p) const; //Legendre符号, 二次剩余, p必须是素数
static Number gcd(Number a, Number b); //最大公约数
static Number gcd(Number a[], int n); //一组数的最大公约数
static void primeTable(int n, deque<Number>& table); //素数表
static Number fabonacci(int n); //Fabonacci数
static Number combinatory(unsigned int n, unsigned int m);
static Number permutation(unsigned int n, unsigned int m);
Number RSA_encryption(Number r, Number e);
Number RSA_decryption(Number r, Number d);
private:
Number powerForIsPrime(Number a, Number p) const; //isPrime的辅助函数,幂余的时候加二次探测
Number pollard() const; //Pollard法求一个因子
public:
UINT64 num;
};
ostream& operator << (ostream& oo,Number& n) //重载插入运算符
{
n.print(oo);
return oo;
}
void Number::print(ostream& oo) const
{
#ifdef _WIN32
printf("%I64u",num);
#elif
printf("%llu",num);
#endif
}
Number Number::rand()
{
return Number(UINT64(::rand()) * ::rand() * ::rand() * ::rand());
}
Number Number::power(unsigned int index) const
{
Number ans = 1;
Number pow = num;
while (index)
{
if (index & 1)
ans.num *= pow.num;
pow.num *= pow.num;
index >>= 1;
}
return ans;
}
Number Number::powerModule(Number index, Number mod) const
{
Number r = 1;
Number pow = num;
while (index.num)
{
if (index.num & 1)
r.num = r.num * pow.num % mod.num;
pow.num = pow.num * pow.num % mod.num;
index.num >>= 1;
}
return r;
}
Number Number::powerForIsPrime(Number a, Number p) const
{
if (p == 0)
return 1;
Number x = powerForIsPrime(a, p/2);
Number result = x*x % num; //二次探测
if (result == 1 && x != 1 && x != num-1) //若num为素数, 则方程x^2≡1的解为x=1或p-1
return 0; //是合数
if (p%2 == 1)
result = result * a % num;
return result;
}
bool Number::isPrime() const
{
if (num <= 1000)
return find(gPrimeTable1000,gPrimeTable1000+168,num) != gPrimeTable1000+168;
for (int time=1; time<10; time++)
{
Number a = rand()%(num-3) + 2;
Number result = powerForIsPrime(a, num-1); //Fermart小定理
if (result == 0 || result != 1)
return false;
}
return true;
}
Number Number::pollard() const
{
for (int j=0; j<168; j++)
if (num % gPrimeTable1000[j] == 0)
return gPrimeTable1000[j];
Number x = rand() % num;
Number y = x;
int k = 2;
for (int i=2; i<1024; i++)
{
x = (x*x - 1) % num;
Number d = gcd(y-x, num);
if (d > 1 && d < num)
return d;
if (i == k)
{
y = x;
k *= 2;
}
}
return 1;
}
void Number::factorization(map<Number,int>& factor) const
{
if (isPrime())
{
factor[num]++;
return;
}
Number d;
for (int t=1; t<=10; t++)
{
d = pollard();
if (d.num != 1)
break;
}
if (d.num == 1)
return;
d.factorization(factor);
(*this/d).factorization(factor);
}
Number Number::eulerFunc() const
{
map<Number,int> factor;
factorization(factor);
Number ans = num;
for (map<Number,int>::const_iterator it=factor.begin(); it!=factor.end(); ++it)
ans = ans * (it->first-1) / it->first;
return ans;
}
Number Number::mobiusFunc() const
{
if (num == 1)
return 1;
map<Number,int> factor;
factorization(factor);
for (map<Number,int>::const_iterator it=factor.begin(); it!=factor.end(); ++it)
if (it->second > 1)
return 0;
if(factor.size() % 2 == 0)
return 1;
else
return -1;
}
int Number::legendre(Number p) const
{
if (num % p.num == 0)
return 0;
else if (powerModule((p-1)/2, p) == 1)
return 1;
else
return -1;
}
Number Number::gcd(Number a, Number b)
{
UINT64 r;
while (b != 0)
{
r = a.num % b.num;
a.num = b.num;
b.num = r;
}
return a;
}
Number Number::gcd(Number a[], int n)
{
if (n < 2)
return 1;
Number d = gcd(a[0], a[1]);
for (int i=2; i<n; i++)
d = gcd(d, a[i]);
return d;
}
void Number::primeTable(int n, deque<Number>& table)
{
for (int i=3; i<n; i+=2)
{
int j;
for (j=0; j<table.size(); j++)
if (i % table[j].num == 0)
break;
if (j == table.size())
table.push_back(i);
}
table.push_front(2);
}
Number Number::combinatory(unsigned int n, unsigned int m)
{
if (m > n)
return 0;
UINT64 ans = 1;
for (int i=0; i<m; i++)
ans = (ans * (n-i)) / (i+1);
return ans;
}
Number Number::permutation(unsigned int n, unsigned int m)
{
if (m > n)
return 0;
UINT64 ans = 1;
for (int i=0; i<m; i++)
ans *= (n-i);
return ans;
}
//RSA加密
//r=p*q为两个大素数的乘积, e与(p-1)*(q-1)互素为明文
Number Number::RSA_encryption(Number r, Number e)
{
return powerModule(e,r);
}
//RSA解密
//r=p*q为两个大素数的乘积, d为密文, d*e≡1 (mod (p-1)*(q-1))
Number Number::RSA_decryption(Number r, Number d)
{
return powerModule(d,r);
}