目录
〇,全文说明、宏定义代码
一,类型计算、二分查找、字典树、字符串处理、几何
二,排列组合
三,代数
四,类型提升、数据结构转换、累积计算、动态规划
五,test
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
所有的代码依赖关系都只体现在类的继承关系中。
所有代码放在一起是可以编译运行的,如果按照章来划分,最后一章是测试代码,其他任意一章都可以单独编译运行。
宏定义代码:
// #define OLD_PLATFORM //旧版本C++就打开这个宏
///(1.1)类型计算///
#define MinValue BasicTypeOpt::minValue//类型最小值
#define ValueNum BasicTypeOpt::valueNum//类型数量
///(1.2)二分查找///
// Bsearch 略。寻找[low,high]中最小的满足Ok条件的数,low<=high,返回值范围是[low,high+1]
///(1.3)字典树///
// Trie 略。字典树
///(1.4)基础字符串处理///
#define StringSplit StringOpt::stringSplit//把字符串按照分隔符拆开成若干字符串
#define StringMatchSplit StringOpt::stringMatchSplit//字符串括号分割,第一行是括号外子串集,第二行是括号内子串集,不含最外层括号
#define StringJoin StringOpt::stringJoin//把字符串列表拼接起来,用分隔符隔开
#define CharToString StringOpt::charToString//char数组/列表转化成string
#define StringToChar StringOpt::stringToChar//string转化成char数组
#define StringToCharVec StringOpt::stringToCharVec//string转化成char列表
///(1.5)子串匹配///
#define GetSameSubStr RabinKarp::getSameSubStr//获得任意一个长为len的重复子串,2个子串可以重叠
#define GetlongestDupSubstring LongestDupSubstring().getlongestDupSubstring//获得任意一个最长重复子串
///(1.6)几何///
// Andrew 略。 求凸包
#define MinMaxWithSlope Geometry().minMaxWithSlope //输入上(下)凸包,从左往右,type为max(min),求y-kx的最大(小)值在哪个点
///(2.1)排列组合///
#define GetAllPermutation Combina::getAllPermutation //在一个列表中选出若干个数,得到所有排列,按照id的字典序来排序
#define IntSplitA Combina::intSplitA//把s拆分成n个不同数的和, 返回所有排列
#define IntSplitC Combina::intSplitC//把s拆分成n个不同数的和, 返回所有组合
///(2.2)数据缓存///
// GetSingleId 略。通用的数据缓存去重编号方案
// GetCombineId 略。对组合型vector数据的优化缓存方案
///(3)代数///
#define MinSumLen Algebra::minSumLen//最小距离问题,给出数轴上若干点,求出到任意点的总距离的最小值
#define EverSumLen Algebra::everSumLen//最小距离问题衍生问题,给出数轴上若干点,求出[low,high]段所有整点到所有点的总距离
// MinExcept 略。(多次)求一个数组内除了某个元素之外的最小值
// CloseInterval 略。区间运算
///(4.1)类型处理///
// UpperType 略。类型提升
///(4.2)数据结构转换///
#define VecTrans BasicOpt::vecTrans//把列表的每个元素进行p转换,p:T1->T2
#define MapTrans BasicOpt::mapTrans//把map的每个pair进行p转换,p:->T2
#define MapTransToVec BasicOpt::mapTransToVec//把map的每个pair进行p转换,p:->T2
#define MapToPairs BasicOpt::mapToPairs//把map转成pair数组
#define DrawFirst BasicOpt::drawFirst//提取pair数组的first
#define DrawSecond BasicOpt::drawSecond//提取pair数组的second
#define GetFirst BasicOpt::getFirst//提取map的first
#define GetSecond BasicOpt::getSecond//提取map的second
#define QueToVec BasicOpt::queToVec//队列转化成数组
#define VecToArr BasicOpt::vecToArr//vector转数组
#define GetNumFromId BasicOpt::getNumFromId//把id数组(一维或二维)转化为对应的数v[id]
#define VectorToMap BasicOpt::vectorToMap//把v1和v2 匹配转化成1个map
#define VmToVector BasicOpt::vmToVector//1个vector加1个map转化成map[vector]
///(4.3)累积计算///
#define GetMultiOpt MultiOpt::getMultiOpt //获取累积计算结果,p:->T2
#define GetMax MultiOpt::getMax //获取vector中最大值
#define GetMax2 MultiOpt::getMax2 //获取二维vector中最大值
#define GetMin MultiOpt::getMin //获取vector中最小值
#define GetMin2 MultiOpt::getMin2 //获取二维vector中最小值
#define GetSum MultiOpt::getSum //获取所有元素之和
#define TransSum MultiOpt::transSum//进行p转换并求和,返回p(v[0])+p(v[1])+...
#define NumInVec2D MultiOpt::numInVec2D//计算二维列表的元素数
///(4.4)动态规划///
// DP_LengthOfLIS 最长上升子序列
// DP_lengthOfEqualDif 最长等差数列
#define MaxSubArrayFromEver DP_MaxSubArray::maxSubArrayFromEver//求以每个元素开头的最大子段和
#define MaxSubArray DP_MaxSubArray::maxSubArray//求最大子段和
#define DP_CoinCombine CoinCombine::dp//输入硬币集{25,10,5,1},总数50,输出组合方案数49
class BasicTypeOpt {
public:
static char minValue(char)
{
return 'a';
}
static int minValue(int)
{
return 0;
}
static int valueNum(char) {
return 26;
}
static int valueNum(int) {
return 10;
}
};
template
class Bsearch //寻找[low,high]中最小的满足isOk条件的数,low<=high,返回值范围是[low,high+getGap()]
{
public:
T find(T low, T high)
{
if (!isOk(high))return high + getGap(high);
if (isOk(low))return low;
T mid;
while (high - low > getGap(low)) {
mid = (high + low) / 2;
if (isOk(mid))high = mid;
else low = mid;
}
return high;
}
private:
virtual bool isOk(T x) const //若isOk(x)且!isOk(y)则必有y 0;
}
int getGap(int) {
return 1;
}
int getGap(long long) {
return 1;
}
double getGap(double) {
return 0.00000001;
}
};
template
class Trie : public BasicTypeOpt
{
public:
vector>v;
mapisEnd;//以任一节点作为尾节点的数目(不一定是叶子节点)
mapdeep;//任一节点的深度
Trie()
{
auto valNum = valueNum(T{});
v.push_back(vector(valNum + 1, 0));
}
void push(const T* s, int len, int value = 0)
{
auto minVal = minValue(T{});
auto valNum = valueNum(T{});
int j = 0;
for (int i = 0; i < len; i++)
{
if (v[j][s[i] - minVal + 1] == 0)
{
v[j][s[i] - minVal + 1] = v.size();
v.push_back(vector(valNum + 1, 0));
deep[v.size() - 1] = i + 1;
}
j = v[j][s[i] - minVal + 1];
}
v[j][0] = value;
isEnd[j]++;
}
int find(const T* s, int len, int& maxDeep, vector& ends)//deep是搜到的最大长度,ends是路过哪些end节点
{
auto minVal = minValue(T{});
int j = 0;
maxDeep = 0;
for (int i = 0; i < len; i++)
{
if (v[j][s[i] - minVal + 1] == 0)return 0;
j = v[j][s[i] - minVal + 1];
maxDeep++;
if (isEnd[j])ends.push_back(j);
}
return v[j][0];
}
int find(const T* s, int len)
{
int maxDeep;
vectorends;
return find(s, len, maxDeep, ends);
}
};
class StringOpt
{
public:
//把字符串按照若干分隔符拆开成若干字符串
static vector stringSplit(string text, map& splitChar)
{
vectorv;
v.clear();
int low = 0, key = 0;
for (int i = 0; i <= text.length(); i++)
{
if (i == text.length() || splitChar[text[i]])//分隔符
{
if (i > low)v.insert(v.end(), text.substr(low, i - low));
low = i + 1;
}
}
return v;
}
//把字符串按照一个分隔符拆开成若干字符串
static vector stringSplit(string text, char splitChar=' ')
{
mapm;
m[splitChar] = 1;
return stringSplit(text, m);
}
//字符串括号分割,第一行是括号外子串集,第二行是括号内子串集,不含最外层括号
static vector> stringMatchSplit(string s, mapm)
{
vector> ans(2);
int start = 0, leftNum = 0;
char tmp;
for (int i = 0; i < s.length(); i++) {
if (leftNum == 0) {
if (m.find(s[i]) != m.end()) {
if (i > start)ans[0].push_back(s.substr(start, i - start));
start = i + 1;
leftNum++;
tmp = s[i];
}
}
else {
if (s[i] == m[tmp]) {
if (--leftNum == 0) {
if (i > start)ans[1].push_back(s.substr(start, i - start));
start = i + 1;
}
}
else if (s[i] == tmp)leftNum++;
}
}
if (s.length() > start)ans[0].push_back(s.substr(start, s.length() - start));
return ans;
}
//把字符串列表拼接起来,用分隔符隔开
static string stringJoin(vectorv, char splitChar)
{
if (v.size() == 0)return "";
string ans = v[0];
for (int i = 1; i < v.size(); i++)ans += splitChar, ans += v[i];
return ans;
}
//char数组转化成string
static string charToString(const char* ch)//ch要自带末尾\0
{
return string(ch);
}
//char列表转化成string
static string charToString(const vector& s)//s要自带末尾\0
{
return charToString(s.data());
}
//string转化成char数组
static char* stringToChar(const string& str)
{
const char* ch = str.data();
return (char*)ch; //强转,慎用
}
//string转化成char列表
static vector stringToCharVec(string& str)
{
char* ch = stringToChar(str);
vectors(ch, ch + str.length());
return s;
}
};
class RabinKarp :public BasicTypeOpt
{
public:
static string getSameSubStr(string s, int len) //获得任意一个长为len的重复子串,2个子串可以重叠
{
bool flag;
vector> v = getStrHash(s, len, flag);
if (flag)return s.substr(v.size(), len);
map, int>m;
for (int i = 0; i < v.size(); i++) {
if (m[v[i]])return s.substr(i, len);
m[v[i]] = 1;
}
return "";
}
private:
static vector> getStrHash(string s, int len, bool& flag)//获取所有长为len的子串的双哈希值
{
flag = false;
vector>ans;
if (s.length() < len)return ans;
long long x1 = 0, x2 = 0, c1 = 1, c2 = 1, p = 1000000007, n1 = valueNum(s[0]), n2 = 49999;
for (int i = 0; i < len; i++) {
x1 = (x1 * n1 + getValue(s[i])) % p, c1 = c1 * n1 % p;
x2 = (x2 * n2 + getValue(s[i])) % p, c2 = c2 * n2 % p;
}
ans.push_back(make_pair(int(x1), int(x2)));
for (int i = len; i < s.length(); i++) {
x1 = (x1 * n1 + p - getValue(s[i - len]) * c1 % p + getValue(s[i])) % p;
x2 = (x2 * n2 + p - getValue(s[i - len]) * c2 % p + getValue(s[i])) % p;
if (x1 == (*ans.rbegin()).first && x2 == (*ans.rbegin()).second) {
flag = true;
return ans;
}
ans.push_back(make_pair(int(x1), int(x2)));
}
return ans;
}
static inline int getValue(char c)
{
return c - minValue(c); //根据实际情况定制MinValue
}
};
class LongestDupSubstring : public RabinKarp, public Bsearch
{
public:
string getlongestDupSubstring(string s) //获得任意一个最长重复子串
{
this->s = s;
int x = 0, m = 1;
for (int i = 1; i < s.length(); i++)if (s[i] == s[i - 1])x++, m = max(m, x); else x = 0;
int len = find(m, s.length() - 1);
return getSameSubStr(s, len - 1);
}
private:
bool isOk(int x)
{
return getSameSubStr(s, x) == "";
}
string s;
};
struct Point
{
double x;
double y;
bool operator<(const Point &p)const
{
if (x == p.x)return y < p.y;
return x < p.x;
}
};
class GeometryBase {
public:
static double slope(Point p1, Point p2)//x一定不同
{
return (p2.y - p1.y) / (p2.x - p1.x);
}
static bool less(double x, double x2) {
return x < x2;
}
static bool lesseq(double x, double x2) {
return x <= x2;
}
};
class Andrew:public GeometryBase //求凸包
{
public:
vectorup, down;//上下半凸包(都是从左往右)
public:
Andrew(bool flag = false) { //flag表示刚好在凸包边上的点是否保留
this->flag = flag;
}
void push(Point p) //从左往右依次push所有的点
{
if (up.empty()) {
up.push_back(p), down.push_back(p), lefts.push_back(p), rights.push_back(p);
return;
}
if(p.x==lefts[0].x)lefts.push_back(p);
if (p.x > up.rbegin()->x) rights.clear();
rights.push_back(p);
if (p.x == up.rbegin()->x) {
if (p.y > up.rbegin()->y)up.rbegin()->y = p.y;
if (p.y < down.rbegin()->y)down.rbegin()->y = p.y;
return;
}
auto cmp = flag ? less : lesseq;
while (up.size() > 1 && cmp(slope(up[up.size() - 2], up[up.size() - 1]) , slope(up[up.size() - 1], p)))up.erase(up.begin() + up.size() - 1);
up.push_back(p);
while (down.size() > 1 && cmp(slope(down[down.size() - 1], p) , slope(down[down.size() - 2], down[down.size() - 1])))down.erase(down.begin() + down.size() - 1);
down.push_back(p);
}
vector getAll() //push之后获取整个凸包,从左下到左上,逆时针
{
vectorans = up;
if (flag) {
sort(rights.begin(), rights.end());
for (int i = 1; i < rights.size() - 1; i++)ans.push_back(rights[i]);
}
if (down.rbegin()->y != up.rbegin()->y)ans.push_back(*down.rbegin());
for (int i = down.size() - 2; i > 0; i--)ans.push_back(down[i]);
if (down.begin()->y != up.begin()->y)ans.push_back(*down.begin());
if (flag) {
sort(lefts.begin(), lefts.end());
for (int i = lefts.size() - 2; i > 0; i--)ans.push_back(lefts[i]);
}
return ans;
}
bool isStraightLine()//是竖线
{
return up.size() < 2;
}
bool isLine()//是线
{
if (isStraightLine())return true;
if (up[0].y != down[0].y)return false;
if (up[1].x != down[1].x || up[1].y != down[1].y)return false;
return true;
}
private:
vectorlefts, rights;
bool flag;
};
class Geometry :public GeometryBase, public Bsearch //几何
{
public:
Point minMaxWithSlope(vector&ps, double k, string type)//输入上(下)凸包,从左往右,type为max(min),求y-kx的最大(小)值在哪个点
{
if (ps.size() == 1)return ps[0];
this->ps = ps, this->k = k, this->type = type;
int id = find(0, ps.size() - 2);
return ps[id];
}
private:
virtual bool isOk(int x) const //若isOk(x)且!isOk(y)则必有y k);
}
private:
string type;
vector ps;
double k;
};
class Combina
{
public:
//在一个列表中选出若干个数,得到所有排列,按照id的字典序来排序
template
static vector> getAllPermutation(const vector& v, int n, bool flag)// flag表示是否去重
{
vector>ans;
if (n <= 0 || n > v.size())return ans;
vectortmp;
mapm;
dfs(n, 1, v, m, tmp, ans, flag);
return ans;
}
//把s拆分成n个不同数的和, 返回所有排列
static vector> intSplitA(int s, int n, const set& m)//m给出了可选的所有数
{
vector>ans;
if (n == 1) {
if (m.find(s) == m.end())return ans;
auto x = vector>(1, vector(1, s));
return x;
}
for (auto p : m) {
setm2 = m;
m2.erase(p);
vector>v = intSplitA(s - p, n - 1, m2);
for (auto& vi : v) {
vi.push_back(p);
ans.push_back(vi);
}
}
return ans;
}
//把s拆分成n个不同数的和, 返回所有组合
static vector> intSplitC(int s, int n, set& m)//m给出了可选的所有数
{
vector>ans;
if (m.empty())return ans;
if (n == 1) {
if (m.find(s) == m.end())return ans;
auto x = vector>(1, vector(1, s));
return x;
}
int p = *m.begin();
m.erase(p);
set m2 = m;
ans = intSplitC(s, n, m);
vector>v = intSplitC(s - p, n - 1, m2);
for (auto& vi : v) {
vi.push_back(p);
ans.push_back(vi);
}
return ans;
}
private:
template
static void dfs(int n, int deep, const vector& v, mapm, vector& tmp, vector>& ans, bool flag)
{
if (deep > n) {
ans.push_back(tmp);
return;
}
mapm2;
for (int i = 0; i < v.size(); i++) {
if (m[i] || (flag && m2[v[i]]))continue;
tmp.push_back(v[i]);
m[i] = 1, m2[v[i]] = 1;
dfs(n, deep + 1, v, m, tmp, ans, flag);
m[i] = 0;
tmp.erase(tmp.end() - 1);
}
}
};
//通用的数据缓存去重编号方案
template
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
for (auto& mi : m)if (mi.second == id)return mi.first;
return T{};
}
private:
mapm;
int n = 0;
};
//对组合型vector数据的优化缓存方案
template
class GetCombineId
{
public:
int id(vector& x)
{
return v2.id(combineId(x));
}
int num()
{
return v2.num();
}
vector getData(int id)
{
vectorids = v2.getData(id);
vectorans(v.size());
for (int i = 0; i < v.size(); i++)ans[i] = v[i].getData(ids[i]);
return ans;
}
private:
vector combineId(vector& x)
{
if (v.empty())v.resize(x.size());
vectorans(x.size());
for (int i = 0; i < x.size(); i++)ans[i] = v[i].id(x[i]);
return ans;
}
private:
vector>v;
GetSingleId>v2;
};
class Algebra
{
public:
//最小距离问题,给出数轴上若干点,求出到任意点的总距离的最小值
template
static T minSumLen(vector& 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
static vector everSumLen(vector v, int low, int high)
{
sort(v.begin(), v.end());
vectorans;
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 (idv[id]) {
s += 1 + abs(v[id] - x) - abs(v[id] - x + 1);
id++;
}
ans.push_back(s);
}
return ans;
}
};
//(多次)求一个数组内除了某个元素之外的最小值
class MinExcept
{
public:
MinExcept(vector& v) :v(v) {
id1 = 0, id2 = 1;
for (int i = 2; i < v.size(); i++) {
if (v[id1] > v[id2])id1 ^= id2 ^= id1 ^= id2;
if (v[i] < v[id2])id2 = i;
}
}
int getMinExcept(int id)
{
if (v[id1] > v[id2])id1 ^= id2 ^= id1 ^= id2;
if (id == id1)return v[id2];
return v[id1];
}
private:
vector& v;
int id1, id2;
};
//闭区间
template //flag=true则[1,2][3,4]可以合并为[1,4],flag=false则不能合并,[1,3][3,4]才可以合并为[1,4]
struct CloseIval
{
int low, high;
CloseIval(int low, int high) :low{ low }, high{ high }
{
x = flag ? 1 : 0;
}
bool operator<(const CloseIval &ci)const
{
return low < ci.low;
}
bool canMerge(const CloseIval &ci) const
{
return ci.low <= high + x && ci.high >= low - x;
}
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 del(const CloseIval &ci)const //canDel==true才调用del
{
vector ans;
if (low < ci.low)ans.push_back({ low,ci.low - x }); // [3, 5]减掉[4, 7] 等于 flag=true?[3, 3]:[3,4]
if (high > ci.high)ans.push_back({ ci.high + x,high });
return ans;//0-2个
}
private:
int x;
};
template
class CloseInterval {
public:
vector>allCi;//所有区间,一直保持排序
//新增区间,如果是尾部插入效率很高,中间插入则效率很低
void push(CloseIval ci)
{
if (allCi.empty()) {
allCi.push_back(ci);
return;
}
auto it = lower_bound(allCi.begin(), allCi.end(), ci);
if (it != allCi.begin())it--;
if (!it->canMerge(ci))it++;
if (it == allCi.end() || !it->canMerge(ci)) {
allCi.insert(it, ci);
return;
}
it->merge(ci);
auto it2 = it;
it2++;
for (; it2 != allCi.end(); it2++) {
if (!it->canMerge(*it2))break;
it->merge(*it2);
}
it++;
while (it2 != allCi.end())*it++ = *it2++;
while (it != allCi.end())allCi.erase(it);
}
//减掉区间,效率很低
void del(CloseIval ci)
{
vector>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;
}
};
#ifdef OLD_PLATFORM
#define UpperType(T) T
#else
template
struct enable {
typedef T type;
};
template
struct enable {
typedef long long type;
};
#define UpperType(T) typename enable>::type
#endif
class BasicOpt
{
public:
//把列表的每个元素进行p转换,p:T1->T2
template
static vector vecTrans(const vector& v, Tfunc p)
{
vectorv2;
transform(v.begin(), v.end(), std::back_inserter(v2), p);
return v2;
}
//把map的每个pair进行p转换,p:->T2,自动变成的pair
template
static map mapTrans(const map& m, Tfunc p)
{
mapm2;
transform(m.begin(), m.end(), std::inserter(m2, m2.end()), [&](const pair& apair) {return make_pair(apair.first, p(apair)); });
return m2;
}
//把map的每个pair进行p转换,p:->T2
template
static vector mapTransToVec(const map& m, Tfunc p)
{
vectorv;
transform(m.begin(), m.end(), std::back_inserter(v), p);
return v;
}
//把map转成pair数组
template
static vector> mapToPairs(const map& m)
{
return mapTransToVec>(m, [](const pair& p) {return p; });
}
//提取pair数组的first
template
static vector drawFirst(const vector>& v)
{
return vecTrans, T1>(v, [](const pair& p) {return p.first; });
}
//提取pair数组的second
template
static vector drawSecond(const vector>& v)
{
return vecTrans, T2>(v, [](const pair& p) {return p.second; });
}
//提取map的first
template
static vector getFirst(const map& m)
{
return drawFirst(mapToPairs(m));
}
//提取map的second
template
static vector getSecond(const map& m)
{
return drawSecond(mapToPairs(m));
}
//队列转化成数组
template
static vector queToVec(queueq) //谨慎传引用
{
vectorv;
while (!q.empty())v.push_back(q.front()), q.pop();
return v;
}
//vector转数组
template
static T* vecToArr(vector& v)
{
return v.data();
}
//把id数组(一维或二维)转化为对应的数v[id]
template
static vector getNumFromId(const vector& v, const vector& id)
{
return vecTrans(id, [&](int i) {return (i >= 0 && i < v.size()) ? v[i] : -1; });
}
template
static vector> getNumFromId(const vector& v, const vector>& id)
{
return vecTrans, vector>(id, [&](const vector& i) {return getNumFromId(v, i); });
}
//把v1和v2 匹配转化成1个map
template
static map vectorToMap(const vector& v1, const vector& v2)
{
mapm;
for (int i = 0; i < v1.size() && i < v2.size(); i++)m[v1[i]] = v2[i];
return m;
}
//1个vector加1个map转化成map[vector]
template
static vector vmToVector(const vector& v, map& m)
{
vectorans;
ans.resize(v.size());
for (int i = 0; i < v.size(); i++)ans[i] = m[v[i]];
return ans;
}
};
class MultiOpt : public BasicOpt
{
public:
//获取累积计算结果,p:->T2
template
static T2 getMultiOpt(T pBegin, T pEnd, Tfunc p)
{
auto it = pBegin;
T2 ans = *it++;
for (; it != pEnd; it++)ans = p(ans, *it);
return ans;
}
//获取vector(一维或二维)中最大值
template
static T getMax(const vector& v)
{
return getMultiOpt(v.begin(), v.end(), [](const T x1, const T x2) {return max(x1, x2); });
}
template
static T getMax2(const vector>& v)
{
return getMax(vecTrans, T>(v, getMax));
}
//获取vector中最小值
template
static T getMin(const vector& v)
{
return getMultiOpt(v.begin(), v.end(), [](const T x1, const T x2) {return min(x1, x2); });
}
//获取二维vector中最小值
template
static T getMin2(const vector>& v)
{
return getMin(vecTrans, T>(v, getMin));
}
//获取所有元素之和
template
static UpperType(T) getSum(const vector& v)
{
return getMultiOpt(v.begin(), v.end(), [](const T x1, const T x2) {return x1 + x2; });
}
//进行p转换并求和,返回p(v[0])+p(v[1])+...
template
static T2 transSum(const vector& v, Tfunc p)
{
return getSum(vecTrans(v, p));
}
//计算二维列表的元素数
template
static int numInVec2D(const vector>& v)
{
return transSum, int>(v, [&](const vector& v) {return v.size(); });
}
};
template
class ArrayDP
{
protected:
ArrayDP(const vector&data, int n)//n表示要求解的范围是[0,n)
{
ans.resize(n);
m = n;
this->data = data;
}
void getAllAns()
{
initAns();
for (int i = lastValueId + 1; i < m; i++)recur(i);
}
inline T2 getAns(int id)
{
if (id < firstValidId || id >= ans.size())return invalidAns;
return ans[id];
}
protected:
virtual void initAns()
{
// 初始化firstValidId和lastValueId和invalidAns,并初始化ans的[firstValidId,lastValueId]这一段的值(最少1个)
}
virtual void recur(int id)
{
//递推式 num[id] = ......
}
protected:
int m;
int firstValidId = 0;
int lastValueId = 0;
T2 invalidAns = T2{};
vectordata;
vectorans;
};
class DP_LengthOfLIS :public ArrayDP>
{
public:
DP_LengthOfLIS(const vector&data, int n, int p = INT_MAX) : ArrayDP(data, n)
{
this->p = p;
getAllAns();
len = num = 0;
for (int i = 0; i < n; i++)if (len < getAns(i).first)len = getAns(i).first, num = getAns(i).second;
else if (len == getAns(i).first)num += getAns(i).second;
}
int getLengthOfLIS()
{
return len;
}
int getNumOfLIS()
{
return num;
}
private:
void initAns()
{
ans[0] = { 1,1 };
}
void recur(int i)
{
ans[i] = { 1, 1 };
for (int j = 0; j < i; j++)
{
if (data[j] <= data[i]) {
if (ans[i].first < ans[j].first + 1)ans[i].first = ans[j].first + 1, ans[i].second = ans[j].second;
else if (ans[i].first == ans[j].first + 1)ans[i].second += ans[j].second, ans[i].second %= p;
}
}
}
int len, num, p;
};
class DP_lengthOfEqualDif :public ArrayDP>
{
public:
DP_lengthOfEqualDif(const vector&data) : ArrayDP(data, data.size())
{
getAllAns();
}
int getLength()
{
return maxans;
}
private:
virtual void recur(int id)
{
for (int pre = 0; pre < id; pre++) {
int d = data[id] - data[pre];
if (ans[pre].count(d))ans[id][d] = ans[pre][d] + 1;
else ans[id][d] = 2; // ans[i][d]表示以data[i]为结尾,公差为d的最长等差数列长度
maxans = max(maxans, ans[id][d]);
}
}
int maxans = 0;
};
class DP_MaxSubArray :public MultiOpt
{
public:
//求以每个元素开头的最大子段和
template
static vector maxSubArrayFromEver(const vector& v)
{
vectorans = v;
for (int i = v.size() - 2; i >= 0; i--) {
if (ans[i + 1] > 0)ans[i] += ans[i + 1];
}
return ans;
}
//求最大子段和
template
static T maxSubArray(const vector& v)
{
return getMax(maxSubArrayFromEver(v));
}
};
class CoinCombine
{
public:
//输入硬币集{25,10,5,1},总数50,输出组合方案数49
static long long dp(vectorcoins, int s, int p = 1000000007)
{
sort(coins.begin(), coins.end());
return dp(coins, s, coins.size() - 1, p);
}
private:
static long long dp(const vector&coins, int s, int id, int p)
{
static map>m;
if (s <= 0 || id < 0)return (s == 0);
if (m[s][id])return m[s][id];
return m[s][id] = (dp(coins, s - coins[id], id, p) + dp(coins, s, id - 1, p)) % p;
}
};
template
static bool isSame(const vector& v1, const vector& 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 testBasicTypeOpt()
{
EXPECT_EQ(MinValue('?'), 'a');
return true;
}
bool testBsearch()//待完善
{
Bsearch{};
return true;
}
bool testTrie()//待完善
{
Trie{};
return true;
}
bool testStringOpt()//待完善
{
string s = "a{b{c}}d(e)f";
mapm;
m['{'] = '}';
m['('] = ')';
auto v = StringMatchSplit(s, m);
EXPECT_VEC_EQ(v[0], (vector{"a", "d", "f"}));
EXPECT_VEC_EQ(v[0], (vector{"b{c}", "e"}));
return true;
}
bool testRabinKarp()//待完善
{
RabinKarp{};
return true;
}
bool testLongestDupSubstring()//待完善
{
LongestDupSubstring{};
return true;
}
bool testAndrewAndMinMaxWithSlope()
{
Andrew andrew;
andrew.push(Point{ 0,0 });
andrew.push(Point{ 1,0.8 });
andrew.push(Point{ 2,2 });
auto down = andrew.down;
Point p = MinMaxWithSlope(down, 1, "min");
EXPECT_EQ(p.x, 1);
EXPECT_EQ(p.y, 0.8);
return true;
}
bool test1()
{
return testBasicTypeOpt() && testBsearch() && testTrie() && testRabinKarp() && testLongestDupSubstring() && testAndrewAndMinMaxWithSlope();
}
bool testCombina()//待完善
{
Combina{};
return true;
}
bool testGetSingleId()//待完善
{
GetSingleId{};
return true;
}
bool testGetCombineId()//待完善
{
GetCombineId{};
return true;
}
bool test2()
{
return testCombina() && testGetSingleId() && testGetCombineId();
}
bool testAlgebra()//待完善
{
vectorv{ 1,3,6 };
auto ans = EverSumLen(v, 0, 5);//{10,7,6,5,6,7}
vectorv2{ 1, 3, 3.3, 6 };
auto ans2 = EverSumLen(v2, 1, 4);//{9.3, 7.3, 5.3, 6.7}
return true;
}
bool testMinExcept()//待完善
{
vectorv;
MinExcept{ v };
return true;
}
bool testCloseInterval()//待完善
{
CloseIval{1, 2};
CloseInterval{};
return true;
}
bool test3()
{
return testAlgebra() && testMinExcept() && testCloseInterval();
}
bool testBasicOpt()//待完善
{
mapm;
m[2] = '4', m[6] = '9';
vectorv1 = GetFirst(m);
vectorv2 = GetSecond(m);
return true;
}
bool testMultiOpt()
{
vectorv{ 1,2,3,5,7 };
EXPECT_EQ(GetMax(v), 7);
vector>v2{ {2,4},{3,1,5} };
EXPECT_EQ(GetMin2(v2), 1);
EXPECT_EQ(GetSum(v), 18);
EXPECT_EQ(NumInVec2D(v2), 5);
}
bool testDP()//待完善
{
vectorv{ 1,2,3,5,7 };
MaxSubArray(v);
EXPECT_EQ(DP_lengthOfEqualDif(v).getLength(), 4);
}
bool test4()
{
return testBasicOpt() && testMultiOpt() && testDP();
}
int main()
{
if (test1() && test2() && test3() && test4())cout << "test succ!";
return 0;
}