目录
〇,全文说明、宏定义代码
一,代数
二,单例、快速幂、数论
二,test
〇,全文说明、宏定义代码
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
所有代码放在一起是可以编译运行的,如果按照章来划分,除了最后一章是测试代码,其他任意一章都可以单独编译运行。
宏定义代码:文章来源:https://www.toymoban.com/news/detail-546562.html
///(1)代数///
#define MinSumLen Algebra::minSumLen//最小距离问题,给出数轴上若干点,求出到任意点的总距离的最小值
#define EverSumLen Algebra::everSumLen//最小距离问题衍生问题,给出数轴上若干点,求出[low,high]段所有整点到所有点的总距离
// CloseInterval 略。闭区间的有序集合
#define GetLowBit Bits::getLowBit //二进制最低位
#define GetHighBit Bits::getHighBit//二进制最高位
#define IsPowerOf2 Bits::isPowerOf2 //是否是2的幂
#define GetBitLength Bits::getBitLength//二进制总位数
#define FgetNum1 Bits::getNum1 //二进制中1的个数
#define FgetNum0 Bits::getNum0 //二进制中0的个数,只算最高位1后面的0
#define GetReverseNum Bits::getReverseNum //二进制反转,01互换,仅限最高位1后面的位
// SemiGroup 略。半群
///(2.1)单例///
// SingleA 略。单例模板
///(2.2)快速乘法、幂、矩阵幂///
// 实现了泛埃及乘法,并泛化成了快速乘法、快速幂、矩阵快速幂。
// 我把接口都写成支持模p的,p的默认值是INT_MAX,需要模p的就给p传值就行。也支持嵌套,只需要扩展op函数即可。
#define MultiAdd Multi::multiAdd//快速乘法
#define MultiMulti Multi::multiMulti//快速幂
#define MultiMultiAdd Multi::multiMultiAdd//快速幂套快速乘法
#define MultiMatrix Multi::multiMatrix//矩阵快速幂
///(2.3)数论基础///
#define NumInRadix NumberTheory::numInRadix //一个数在d进制下的位数
#define IntToStr NumberTheory::intToStr //把整数转化为字符串,返回值是字符串长度
#define StrToInt NumberTheory::strToInt //把字符串转化为整数
#define IntRev NumberTheory::intRev//整数翻转,输入120,10,输出21
#define IsPrime NumberTheory::isPrime // 素数检测
#define GetHighNum NumberTheory::getHighNum //把3245分解成3*1000+245,出参a=3 b=1000 c=245
#define IsHas9 NumberTheory::isHas9 //一个十进制数里面有没有数字9
#define NumHas9 NumberTheory::numHas9 //1-n中有多少十进制数里面有数字9,n<10^9
#define IsPalindrome NumberTheory::isPalindrome //是否为回文数
#define Gcd NumberTheory::gcd //最大公约数
#define Lcm NumberTheory::lcm //最小公倍数
///(2.4)数论进阶///
#define IsPrime2 Sieve::GetSingleA().isPrime//判断n是不是素数
#define GetPrime Sieve::GetSingleA().getPrime//获取[1,n]内的所有素数
#define Fenjie Facs::fenjie //因式分解
#define Fenjie2 Facs::fenjie2 //因式分解
#define GetFacs Facs::getFacs //获取所有因子
#define GetMaxFacs Facs::getMaxFacs//获取最大因子
#define GetDivisors Facs::getDivisors//获取所有约数
#define IsSquareSum Facs::isSquareSum//判断是不是平方和
#define GetPhi Phi::getPhi//欧拉函数
#define GetFacsOfPhi Phi::getFacsOfPhi//计算phi(n)的所有因子facs,返回phi(n)
#define GetOrder Order::getOrder//求a mod n的阶
#define DiscreteLog BSGS::discreteLog//求离散对数a^x=b(mod p)
#define FactorialDegree Factorial::degree //求m!中素数p的次数
#define FactorialDegree2 Factorial::degree2 //求m!中n的次数
#define FactorialFactorization Factorial::factorization //求n!的因式分解
// ComNum 略
一,代数
class Algebra
{
public:
//最小距离问题,给出数轴上若干点,求出到任意点的总距离的最小值
template<typename T>
static T minSumLen(vector<T>& v)
{
sort(v.begin(), v.end());
T mid = (v[(v.size() - 1) / 2] + v[v.size() / 2]) / 2;
T ans = 0;
for (int i = 0; i < v.size(); i++)ans += abs(v[i] - mid);
return ans;
}
//最小距离问题衍生问题,给出数轴上若干点,求出[low,high]段所有整点到所有点的总距离
template<typename T>
static vector<T> everSumLen(vector<T> v, int low, int high)
{
sort(v.begin(), v.end());
vector<T>ans;
int x = low, id = 0;
T s = 0;
for (auto vi : v)s += abs(vi - x), id += (vi < x);
ans.push_back(s);
for (x = low + 1; x <= high; x++) {
s += id * 2 - int(v.size());
while (id<v.size() && x>v[id]) {
s += 1 + abs(v[id] - x) - abs(v[id] - x + 1);
id++;
}
ans.push_back(s);
}
return ans;
}
};
//闭区间,type=0表示整点区间,type=1表示整段区间,type=2表示浮点数区间
template<int type, typename T = int> //type=2 T=float type<2 T=int
struct CloseIval
{
T low, high;
CloseIval() {}
CloseIval(T low, T high) :low{ low }, high{ high }
{
gap = (type ? 0 : 1);
}
bool operator<(const CloseIval& ci)const //按照左端点进行排序
{
return low < ci.low;
}
bool canMerge(const CloseIval& ci) const
{
return ci.low <= high + gap && ci.high >= low - gap;
}
void merge(const CloseIval& ci) //canMerge==true才调用merge
{
low = min(low, ci.low), high = max(high, ci.high);
}
bool canDel(const CloseIval& ci) const //对于浮点数区间,减法定义不严谨,慎用
{
return canMerge(ci);
}
vector<CloseIval> del(const CloseIval& ci)const //canDel==true才调用del
{
vector<CloseIval> ans;
if (low < ci.low)ans.push_back({ low,ci.low - gap });
if (high > ci.high)ans.push_back({ ci.high + gap,high });
return ans;//0-2个
}
private:
T gap;
};
//闭区间的有序集合,type=0表示整点区间,type=1表示整段区间,type=2表示浮点数区间
template<int type, typename T = int> //type=2 T=float type<2 T=int
class CloseInterval {
public:
using Ival = CloseIval<type, T>;
vector<Ival>allCi;//所有区间,一直保持排序
public:
//新增区间,尾部插入效率是O(log n),中间插入效率是O(n)
void push(Ival ci)
{
auto it = lower_bound(allCi.begin(), allCi.end(), ci);
auto it2 = it;
bool canMergeFlag = it!= allCi.end() && it->canMerge(ci);
bool canMergeFlag2 = false;
if (it != allCi.begin()) {
it--; //可能可以merge的第一个区间
canMergeFlag2 = it->canMerge(ci);
}
if (!canMergeFlag && !canMergeFlag2) {
allCi.insert(it2, ci);
return;
}
if (!canMergeFlag2)it = it2;
//此时it是可以merge的第一个区间
it->merge(ci);
it2 = it;
it2++;
for (; it2 != allCi.end(); it2++) {
if (!it->canMerge(*it2))break;
it->merge(*it2); //往后把所有能merge的都merge到第一个区间
}
it++;
while (it2 != allCi.end())*it++ = *it2++; //剩下没merge的往前平移
allCi.resize(it - allCi.begin());
}
//减掉区间,效率是O(n)
void del(Ival ci)
{
vector<Ival>ans;
for (auto any : allCi) {
if (any.canMerge(ci)) {
auto tmp = any.del(ci);
for (auto t : tmp)ans.push_back(t);
}
else ans.push_back(any);
}
allCi = ans;
}
};
//二进制运算,n>0
class Bits {
public:
//二进制最低位
static inline long long getLowBit(long long n) {
return n & (-n);
}
//二进制最高位
static inline long long getHighBit(long long n) {
while (n != getLowBit(n)) n ^= getLowBit(n);
return n;
}
//是否是2的幂
static inline bool isPowerOf2(long long n) {
return n == getLowBit(n);
}
//二进制总位数
static inline int getBitLength(long long n) {
int ans = 0;
while (n)
{
n >>= 1;
ans++;
}
return ans;
}
//二进制中1的个数
static inline int getNum1(long long n) {
int ans = 0;
while (n)
{
n ^= getLowBit(n);
ans++;
}
return ans;
}
//二进制中0的个数,只算最高位1后面的0
static inline int getNum0(long long n) {
return getBitLength(n) - getNum1(n);
}
//二进制反转,01互换,仅限最高位1后面的位
static inline long long getReverseNum(long long n) {
long long a = 1, len = getBitLength(n);
return (a << len) - 1 ^ n;
}
};
//半群
class SemiGroup
{
public:
//枚举只去掉1个数(v.size()>1),剩下的数做p累积运算的结果
template<typename T, typename Tfunc>
static vector<T> allExceptOne(vector<T>& v, Tfunc p) {
vector<T>left(v.size() - 1), right(v.size() - 1);
T x = v[0];
for (int i = 1; i < v.size(); i++)left[i - 1] = x, x = p(x, v[i]);
x = v.back();
for (int i = int(v.size()) - 2; i >= 0; i--)right[i] = x, x = p(v[i], x);
vector<T>ans(1, right[0]);
for (int i = 0; i < left.size() - 1; i++)ans.push_back(p(left[i], right[i + 1]));
ans.push_back(left.back());
return ans;
}
};
二,单例、快速幂、数论
template<typename T>
class SingleA {
public:
static T& GetSingleA() {
static T s;
return s;
}
protected:
SingleA(const SingleA&) = delete;
SingleA(SingleA&&) = delete;
SingleA& operator=(const SingleA&) = delete;
SingleA& operator=(SingleA&&) = delete;
SingleA() = default;
~SingleA() = default;
};
class Multi
{
public:
template<typename N>
static long long multiAdd(long long a, N n, int p = INT_MAX)//快速乘法,n>0
{
return aijiMulti(a, n, p, opAdd<long long>);
}
template<typename N>
static long long multiMulti(long long a, N n, int p = INT_MAX)//快速幂,n>0
{
return aijiMulti(a, n, p, opMulti<long long>);
}
template<typename N>
static long long multiMultiAdd(long long a, N n, int p = INT_MAX)//快速幂套快速乘法,n>0
{
return aijiMulti(a, n, p, opMultiAdd<long long>);
}
template<typename A, typename N>
static vector<vector<A>> multiMatrix(vector<vector<A>> a, N n, int p = INT_MAX)//矩阵快速幂,n>0
{
return aijiMulti(a, n, p, opMatrixMulti<A>);
}
protected:
template<typename A>
static inline A opAdd(A x, A y, int p)
{
return (x + y) % p;
}
template<typename A>
static inline A opMulti(A x, A y, int p)
{
return (x * y) % p;
}
template<typename A>
static inline A opMultiAdd(A x, A y, int p)
{
return aijiMulti(x, y, p, opAdd<A>);
}
template<typename A>
static inline vector<vector<A>> opMatrixMulti(vector<vector<A>> x, vector<vector<A>> y, int p)
{
vector<vector<A>> ans = x;
for (int i = 0; i < ans.size(); i++) {
for (int j = 0; j < ans.size(); j++) {
ans[i][j] = 0;
for (int k = 0; k < ans.size(); k++)ans[i][j] += (x[i][k] * y[k][j]) % p;
}
}
return ans;
}
template<typename A, typename N>
static inline A aijiMulti(A a, N n, int p, A(*pfunc)(A, A, int))
{
if (n <= 1)return a;
A ans = aijiMulti<A, N>(a, n / 2, p, pfunc);
ans = pfunc(ans, ans, p);
if (n % 2)ans = pfunc(ans, a, p);
return ans;
}
};
class NumberTheory
{
public:
//一个数在d进制下的位数
static int numInRadix(long long m, int d)
{
if (m == 0)return 1;
int s = 0;
while (m)
{
s++;
m /= d;
}
return s;
}
//把整数转化为字符串, 出参str不用初始化,返回值是字符串长度
static int intToStr(long long num, unsigned radix, char*& str)
{
int len = numInRadix(num, radix);
str = new char[len + 2];
char index[] = "0123456789ABCDEF";
int k = 0;
if (num < 0)str[0] = '-', k = 1;
num = abs(num);
for (int i = len - 1 + k; i >= k; i--)
{
str[i] = index[num % radix], num /= radix;
}
str[len + k] = '\0';
return len + k;
}
//把字符串转化为整数
static long long strToInt(const char* nptr, int radix) //库函数atoi只支持十进制
{
int k = 0;
if (*nptr == '-')k = 1, nptr++;
long long ans = 0;
while (*nptr) {
int x = (*nptr >= '0' && *nptr <= '9') ? *nptr - '0' : *nptr - 'A';
ans = ans * radix + x, nptr++;
}
return k ? -ans : ans;
}
// 素数检测
static bool isPrime(int n)
{
if (n == 2)return true;
if (n % 2 == 0)return false;
for (int i = 3; i * i <= n; i += 2) if (n % i == 0)return false;
return true;
}
//把3245分解成3*1000+245,出参a=3 b=1000 c=245
static void getHighNum(int n, int& a, int& b, int& c)
{
int m = n;
b = 1;
m /= 10;
while (m)b *= 10, m /= 10;
a = n / b, c = n % b;
}
//一个十进制数里面有没有数字9
static bool isHas9(int n)
{
while (n) {
if (n % 10 == 9)return true;
n /= 10;
}
return false;
}
//1-n中有多少十进制数里面有数字9,n<10^9
static int numHas9(int n)
{
if (n <= 1)return 0;
int num[10] = { 0,1,19,271,3439,40951,468559,5217031,56953279,612579511 };
int a, b, c;
getHighNum(n, a, b, c);
int d = 0;
while (b > 1)d++, b /= 10;
return a * num[d] + (a == 9 ? c + 1 : isHas9(c));
}
//是否为回文数
static bool isPalindrome(int x)
{
if (x < 0)return false;
vector<int>num;
while (x)
{
num.insert(num.end(), x % 10);
x /= 10;
}
int len = num.size();
for (int i = 0, j = len - 1; i < j; i++, j--)
{
if (num[i] - num[j])return false;
}
return true;
}
//最大公约数
static long long gcd(long long a, long long b)
{
if (b == 0)return a;
return gcd(b, a % b);
}
//最小公倍数
static long long lcm(long long a, long long b)
{
a /= gcd(a, b);
if (a > LLONG_MAX / b)return 0;
return a * b;
}
};
class Sieve : public SingleA<Sieve>
{
static const int N = 200000;
friend class SingleA<Sieve>;
public:
bool isPrime(int n)//判断n是不是素数
{
if (n < 2)return false;
calPrime(n);
return prime[n];
}
vector<int> getPrime(int n)//获取[1,n]内的所有素数,如果曾经传过更大的N,则返回[1,N]内的所有素数
{
if (n < 2)return vector<int>{};
calPrime(n);
return vPrime;
}
private:
Sieve() {
prime[0] = prime[1] = 0, prime[2] = 1;
flag = 2;
for (int i = 3; i < N; i += 2)prime[i] = 1;
vPrime.reserve(N / 5);
vPrime.push_back(2);
}
void calPrime(int n)//判断[1,n]内的素数,n<N
{
if (flag >= n)return;
for (int i = flag + 1 + flag % 2; i <= n; i += 2)if (prime[i])
{
vPrime.push_back(i);
for (int j = i + i; j < N; j += i)prime[j] = 0;
}
flag = n;
}
private:
int flag;
int prime[N];
vector<int>vPrime;
};
class Facs:public Sieve
{
public:
//因式分解,把12分解成{<2,2>,<3,1>}
static vector<pair<int, int>> fenjie(int n)
{
vector<pair<int, int>> vp;
for (auto i : GetSingleA().getPrime(sqrt(n + 1)))
{
if (n % i)continue;
int k = 0;
while (n % i == 0)n /= i, k++;
vp.push_back({ i, k });
}
if (n > 1) vp.push_back({ n, 1 });
return vp;
}
//积性分解,即单素数幂分解,把12分解成{4,3}
static vector<int> fenjie2(int n)
{
vector<pair<int, int>> vp = fenjie(n);
vector<int>ans;
for (auto vi : vp) {
int s = 1;
while (vi.second--)s *= vi.first;
ans.push_back(s);
}
return ans;
}
//获取所有因子
static vector<int> getFacs(int n)
{
vector<pair<int, int>> vp = fenjie(n);
vector<int>ans;
for (auto vi : vp)ans.push_back(vi.first);
return ans;
}
//获取最大因子
static int getMaxFacs(int n)
{
vector<int> v = getFacs(n);
return *v.rbegin();
}
//获取所有约数
static vector<int> getDivisors(int n)
{
vector<pair<int, int>>v = fenjie(n);
vector<int>ans, ans2;
ans.push_back(1);
if (n <= 1)return ans;
for (auto vi : v) {
vector<int>ans2(ans.size() * (vi.second + 1));
copy(ans.begin(), ans.end(), ans2.begin());
for (int i = ans.size(); i < ans2.size(); i++) ans2[i] = ans2[i - ans.size()] * vi.first;
ans = ans2;
}
sort(ans.begin(), ans.end());
return ans;
}
static int findNear(int x, int a) // 1<a<x
{
auto v = getDivisors(x);
for (int i = 0; i < v.size(); i++) {
if (v[i + 1] <= a)continue;
if (v[i] + v[i + 1] - a * 2 > 0)return v[i];
return v[i + 1];
}
return 0;
}
//判断是不是平方和
static bool isSquareSum(int n)
{
vector<pair<int, int>> vp = fenjie(n);
for (auto &p : vp) {
if (p.first % 4 == 3 && p.second % 2 == 1)return false;
}
return true;
}
};
class Phi :public Facs
{
public:
//欧拉函数
static int getPhi(int n)
{
static map<int, int>m;
if (m[n])return m[n];
return m[n] = getPhiWithFacs(n, getFacs(n));
}
//计算phi(n)的所有因子facs,返回phi(n)
static int getFacsOfPhi(int n, vector<int>& facs)
{
vector<pair<int, int>> vp = fenjie(n);
vector<int>v;
set<int>facSet;
for (auto vi : vp) {
v.push_back(vi.first);
if (vi.second > 1)facSet.insert(vi.first);
for (auto x : getFacs(vi.first - 1))facSet.insert(x);
}
for (auto x : facSet)facs.push_back(x);
return getPhiWithFacs(n, v);
}
private:
//已知n的所有因子,求欧拉函数
static int getPhiWithFacs(int n, const vector<int>& v)
{
int ans = n;
for (auto vi : v)ans = ans / vi * (vi - 1);
return ans;
}
};
class Order :public Phi, public NumberTheory, public Multi
{
public:
//求a mod n的阶,-1表示不存在
static int getOrder(int a, int n)
{
if (gcd(a, n) != 1)return -1;
vector<int> facsOfPhi;
int thephi = getFacsOfPhi(n, facsOfPhi);
return getOrder(a, n, thephi, facsOfPhi);
}
private:
//求a mod n的阶,一定是upPie的约数
static int getOrder(int a, int n, int upPie, vector<int>& facsOfPhi)
{
for (auto vi : facsOfPhi) {
while (upPie % vi == 0 && multiMulti(a, upPie / vi, n) % n == 1)upPie /= vi;
}
return upPie;
}
};
class BSGS :public Order //求离散对数a^x=b(mod p)
{
public:
static long long discreteLog(long long a, long long b, int p)
{
a = (a % p + p) % p, b = (b % p + p) % p;
if (a == 0)return (b == 0) ? 1 : -1;
int maxLog = getOrder(a, p);
long long m = (long long)sqrt(double(maxLog));
long long c = multiMulti(a, p - 1 - m, p);
set<long long>s;
map<long long, long long>ma;
long long x = 1;
for (int j = 0; j < m; j++) {
if (j > 0 && x == 1)break;
s.insert(x);
ma[x] = j;
x = x * a % p;
}
for (int i = 0; i <= maxLog / m; i++) {
if (s.find(b) != s.end()) {
return i * m + ma[b];
}
b = b * c % p;
}
return -1;
}
};
class Factorial:public Facs
{
public:
static inline int degree(int m, int p)//求m!中素数p的次数
{
int ans = 0;
while (m)ans += m / p, m /= p;
return ans;
}
static inline int degree2(int m, int n)//求m!中n的次数
{
vector<pair<int, int>> vp = fenjie(n);
int ans = degree(m, vp[0].first) / vp[0].second;
for (int i = 1; i < vp.size(); i++)ans = min(ans, degree(m, vp[i].first) / vp[i].second);
return ans;
}
static vector<pair<int, int>> factorization(int n) //求n!的因式分解
{
vector<pair<int, int>> vp;
for (auto i : GetSingleA().getPrime(n)) {
if (i > n)break;
vp.push_back({ i, degree(n,i) });
}
return vp;
}
};
class ComNum :public Factorial
{
public:
static vector<pair<int, int>> fenjie(int n, int k) //组合数C(n,k)的因式分解
{
auto ps = Sieve::GetSingleA().getPrime(n + k);
vector<pair<int, int>> ans;
for (auto p : ps) {
int mi = degree(n, p) - degree(k, p) - degree(n - k, p);
if (mi)ans.push_back(make_pair(p, mi));
}
return ans;
}
static int getValue(int n, int k, int p = INT_MAX) //组合数C(n,k)%p
{
vector<pair<int, int>> v = fenjie(n, k);
long long ans = 1;
for (auto par : v)
{
int mi = par.second;
while (mi--)ans = ans * par.first%p;
}
return ans;
}
};
三,test
测试代码还比较拉垮,先测试编译问题。文章来源地址https://www.toymoban.com/news/detail-546562.html
template<typename T>
static bool isSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (v1[i] != v2[i])return false;
return true;
}
#define EXPECT_VEC_EQ(a,b) if(!isSame((a),(b))){cout<<"ERROR!!!!!!!!!\n";return false;}
#define EXPECT_EQ(a,b) if(a!=b){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testAlgebra()//待完善
{
vector<int>v{ 1,3,6 };
auto ans = EverSumLen(v, 0, 5);//{10,7,6,5,6,7}
vector<double>v2{ 1, 3, 3.3, 6 };
auto ans2 = EverSumLen(v2, 1, 4);//{9.3, 7.3, 5.3, 6.7}
return true;
}
bool testMinExcept()//待完善
{
vector<int>v;
MinExcept{ v };
return true;
}
bool testCloseInterval()//待完善
{
CloseIval<true>{1, 2};
CloseInterval<true>{};
return true;
}
bool test1()
{
return testAlgebra() && testMinExcept() && testCloseInterval();
}
bool testMulti()//待完善
{
EXPECT_EQ(MultiMulti(2, 10), 1024);
return true;
}
bool testNumberTheory()//待完善
{
NumberTheory{};
return true;
}
bool testSieve()//待完善
{
Sieve::GetSingleA();
return true;
}
bool testFacs()//待完善
{
Facs::fenjie(100);
return true;
}
bool testPhi()//待完善
{
Phi::getPhi(100);
return true;
}
bool testOrder()//待完善
{
Order::getOrder(10, 100);
return true;
}
bool testBSGS()//待完善
{
BSGS::discreteLog(2, 1, 97);
return true;
}
bool testFactorial()//待完善
{
return true;
}
bool testComNum()//待完善
{
return true;
}
bool test2()
{
return testMulti() && testNumberTheory() && testSieve() && testFacs() && testPhi() && testOrder() && testBSGS()
&& testFactorial() && testComNum();
}
int main()
{
if (test1() && test2())cout << "test succ!";
return 0;
}
到了这里,关于ACM模板(快速幂、数论、图论)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!