目录
〇,全文说明、宏定义代码
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
代码工程结构:
- 每一章的第一节《代码》可以独立编译运行(本地要加LOCAL宏)
- 每一章的第二节《测试代码》搭配第〇章的代码和本章第一节的代码可以编译运行并测试成功
- 所有模板文章的第〇章的代码和其他章第一节的《代码》全部汇总起来可以编译运行
宏定义代码:
// #define OLD_PLATFORM //旧版本C++就打开这个宏
///(1)二分查找///
// Bsearch 略。寻找[low,high]中最小的满足Ok条件的数,low<=high,返回值范围是[low,high+1]
///(2.1)类型计算///
#define MinValue BasicTypeOpt::minValue//类型最小值
#define ValueNum BasicTypeOpt::valueNum//类型数量
///(2.2)字典树///
// Trie 略。字典树
///(3.1)基础字符串处理///
#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列表
///(3.2)子串匹配///
#define GetSameSubStr RabinKarp::getSameSubStr//获得任意一个长为len的重复子串,2个子串可以重叠
#define GetlongestDupSubstring LongestDupSubstring().getlongestDupSubstring//获得任意一个最长重复子串
//KMP 略
//OrderMatch 略。偏序匹配
///(4)几何///
#define Slope GeometryBase::slope //求2点斜率
#define PointDistance GeometryBase::pointDistance //求2点距离
#define InCircle GeometryBase::inCircle //判断点是否在圆内
#define IsParallels GeometryBase::isParallels // 两直线是否平行
#define IsSameLine GeometryBase::isSameLine // 两直线是否重叠
#define IntersectionLineAndLine GeometryBase::intersectionLineAndLine // 两直线交点,仅在不平行时才能调用
#define PointInSegment GeometryBase::pointInSegment //已知线段se和点p在一条直线上,判断p是否在se之间(包括se)
#define IsSameSide GeometryBase::isSameSide//2点是否在直线同侧,包括点在直线上也算
#define IsPointInLine GeometryBase::isPointInLine//点是否在直线上
#define GetPosStatus GeometryBase::getPosStatus // 求凸多边形和直线的4种位置关系,如果相交则输出交点
#define GetMaxSlope GeometryBase::getMaxSlope //求点集中任意两点斜率的最大值
#define GetMinSlope GeometryBase::getMinSlope //求点集中任意两点斜率的最小值
// Andrew 略。 求凸包
#define MinMaxWithSlope Geometry().minMaxWithSlope //输入上(下)凸包,从左往右,type为max(min),求y-kx的最大(小)值在哪个点
///(5.1)类型处理///
// UpperType 略。类型提升
///(5.2)数据结构转换///
#define VecTrans BasicOpt::vecTrans//把列表的每个元素进行p转换,p:T1->T2
#define MapTrans BasicOpt::mapTrans//把map的每个pair进行p转换,p:<T0,T1>->T2
#define MapTransToVec BasicOpt::mapTransToVec//把map的每个pair进行p转换,p:<T0,T1>->T2
#define MapToPairs BasicOpt::mapToPairs//把map转成pair数组
#define DrawFirst BasicOpt::drawFirst//提取pair数组的first
#define DrawSecond BasicOpt::drawSecond//提取pair数组的second
#define GetMapFirst BasicOpt::getMapFirst//提取map的first
#define GetMapSecond BasicOpt::getMapSecond//提取map的second
#define StackToVec BasicOpt::stackToVec//栈转化成数组
#define QueToVec BasicOpt::queToVec//队列转化成数组
#define VecToArr BasicOpt::vecToArr//vector转数组
#define GetNumFromId BasicOpt::getNumFromId//把id数组(一维或二维)转化为对应的数v[id]
#define VectorToMap BasicOpt::vectorToMap//把v1和v2 匹配转化成1个map<v1,v2>
#define VmToVector BasicOpt::vmToVector//1个vector加1个map转化成map[vector]
///(5.3)累积计算///
#define GetMultiOpt MultiOpt::getMultiOpt //获取累积计算结果,p:<T2,T>->T2
#define GetVecMax MultiOpt::getVecMax //获取vector中最大值
#define GetVecMax2 MultiOpt::getVecMax2 //获取二维vector中最大值
#define GetVecMin MultiOpt::getVecMin //获取vector中最小值
#define GetVecMin2 MultiOpt::getVecMin2 //获取二维vector中最小值
#define GetVecSum MultiOpt::getVecSum //获取所有元素之和
#define TransSum MultiOpt::transSum//进行p转换并求和,返回p(v[0])+p(v[1])+...
#define NumInVec2D MultiOpt::numInVec2D//计算二维列表的元素数
///(5.4)动态规划///
// ArrayDP 数列DP
// DP_LengthOfLIS 最长上升子序列
// DP_lengthOfEqualDif 最长等差数列
#define MaxSubArrayFromEver DP_MaxSubArray::maxSubArrayFromEver//求以每个元素开头的最大子段和
#define MaxSubArray DP_MaxSubArray::maxSubArray//求最大子段和
一,二分查找
1,代码
template<typename T>
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) //若isOk(x)且!isOk(y)则必有y<x
{
return x > 0;
}
int getGap(int) {
return 1;
}
int getGap(long long) {
return 1;
}
double getGap(double) {
return 0.00000001;
}
};
2,测试代码
#define EXPECT_EQ(a,b) if(a!=b){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testBsearch()//待完善
{
Bsearch<int>{};
return true;
}
int main()
{
if (testBsearch())cout << "test succ!";
return 0;
}
二,类型计算、字典树
1,代码
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<typename T>
class Trie : public BasicTypeOpt
{
public:
vector<vector<int>>v;
map<int, int>isEnd;//以任一节点作为尾节点的数目(不一定是叶子节点)
map<int, int>deep;//任一节点的深度
Trie()
{
auto valNum = valueNum(T{});
v.push_back(vector<int>(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<int>(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<int>& 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;
vector<int>ends;
return find(s, len, maxDeep, ends);
}
};
2,测试代码
#define EXPECT_EQ(a,b) if(a!=b){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testBasicTypeOpt()
{
EXPECT_EQ(MinValue('?'), 'a');
return true;
}
bool testTrie()//待完善
{
Trie<int>{};
return true;
}
int main()
{
if (testBasicTypeOpt() && testTrie())cout << "test succ!";
return 0;
}
三,字符串处理、串匹配
1,代码
class StringOpt
{
public:
//把字符串按照若干分隔符拆开成若干字符串
static vector<string> stringSplit(string text, map<char, int>& splitChar)
{
vector<string>v;
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<string> stringSplit(string text, char splitChar = ' ')
{
map<char, int>m;
m[splitChar] = 1;
return stringSplit(text, m);
}
//字符串括号分割,第一行是括号外子串集,第二行是括号内子串集,不含最外层括号
static vector<vector<string>> stringMatchSplit(string s, map<char, char>m)
{
vector<vector<string>> 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(vector<string>v, 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<char>& 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<char> stringToCharVec(string& str)
{
char* ch = stringToChar(str);
vector<char>s(ch, ch + str.length());
return s;
}
};
class RabinKarp
{
public:
static string getSameSubStr(string s, int len) //获得任意一个长为len的重复子串,2个子串可以重叠
{
bool flag;
vector<pair<int, int>> v = getStrHash(s, len, flag);
if (flag)return s.substr(v.size(), len);
map<pair<int, int>, 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<pair<int, int>> getStrHash(string s, int len, bool& flag)//获取所有长为len的子串的双哈希值
{
flag = false;
vector<pair<int, int>>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);
}
static inline char minValue(char) //根据实际情况定制MinValue
{
return 'a';
}
static inline int valueNum(char)
{
return 26;
}
};
class LongestDupSubstring : public RabinKarp
{
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:
using T = int;
T find(T low, T high)
{
if (!isOk(high))return high + 1;
if (isOk(low))return low;
T mid;
while (high - low > 1) {
mid = (high + low) / 2;
if (isOk(mid))high = mid;
else low = mid;
}
return high;
}
bool isOk(int x)
{
return getSameSubStr(s, x) == "";
}
string s;
};
template <typename T = char>
class KMP {
public:
// 输出长为m+1的next数组,next[0]废弃
static vector<int> getNext(const T *p, int m)
{
int i = 1, j = 0;
vector<int>next(m + 1);
next[0] = next[1] = 0;
while (i < m)
{
if (j == 0 || p[i - 1] == p[j - 1])next[++i] = ++j;
else j = next[j];
}
return next;
}
// 输出长为m+1的改进next数组,next[0]废弃
static vector<int> getNextVal(const T *p, int m)
{
int i = 1, j = 0;
vector<int>next(m + 1);
next[0] = next[1] = 0;
while (i < m)
{
if (j == 0 || p[i - 1] == p[j - 1])
{
if (p[i++] != p[j++])next[i] = j;
else next[i] = next[j];
}
else j = next[j];
}
return next;
}
// 求末尾至少添加多少字符才能变成周期串(至少出现2段周期)
static int addToCircle(const T *p, int m)
{
vector<int> next = getNext(p, m);
int k = next[m];
while (k && p[m - 1] != p[k - 1])k = next[k];
int dif = m - k;
return (dif - m % dif) % dif + (!k)*m;
}
// 求最小周期
static int minCircle(const T *p, const vector<int> &next, int m)
{
int dif = m - next[m];
if (m%dif == 0 && p[m - 1] == p[next[m] - 1])return dif;
return m;
}
// 求最小周期
static int minCircle(const T *p, int m)
{
return minCircle(p, getNext(p, m), m);
}
// 输入主串和模式串,求最大匹配数(主串匹配出来的串不能互相覆盖)
static int maxMatchNum(const T *pn, int n, const T* pm, int m)
{
int sum = 0, x = -m;
vector<int> v = allMatchId(pn, n, pm, m);
for (auto vi : v) {
if (vi >= x + m)sum++, x = vi;
}
return sum;
}
// 输入主串和模式串,求最大匹配数(主串匹配出来的串可以互相覆盖)
static int maxMatchNum2(const T *pn, int n, const T* pm, int m)
{
return allMatchId(pn, n, pm, m).size();
}
// 输入主串和模式串,求最大连续匹配数
static int maxMatchNum3(const T *pn, int n, const T* pm, int m)
{
return longestSubsequence(allMatchId(pn, n, pm, m), m);
}
// 求第一个匹配的坐标(范围是1到n-m+1),没有就返回-1
static int firstMatchId(const T *pn, int n, const T* pm, int m)
{
vector<int> v = allMatchId(pn, n, pm, m);
return v.size() ? v[0] : -1;
}
private:
// 输入主串和模式串,求所有匹配id(范围是1到n-m+1)
static vector<int> allMatchId(const T *pn, int n, const T* pm, int m)
{
vector<int>ans;
vector<int>next = getNext(pm, m);
int i = 0, j = 0;
while (i < n)
{
if (pn[i] == pm[j])
{
i++;
if (++j >= m)ans.push_back(i - m + 1), j = next[j];
}
else
{
if (next[j + 1])j = next[j + 1] - 1;
else i++, j = 0;
}
}
return ans;
}
static int longestSubsequence(const vector<int>& arr, int difference) {
map<int, int>ans;
int res = 0;
for (int i = 0; i < arr.size(); i++)
{
ans[arr[i]] = max(ans[arr[i]], ans[arr[i] - difference] + 1);
res = max(res, ans[arr[i]]);
}
return res;
}
};
struct Node {
int p[100005];
int num[100005][26]; //num[i][j]是p前i个数中不超过j的数的个数
};
Node nodes, nodet;
class OrderMatch {
public:
OrderMatch(Node &nodes, Node &nodet)
{
this->nodes = nodes, this->nodet = nodet;
}
vector<int> match(int n, int m)
{
vector<int>next = getNext(nodet, m);
int i = 0, j = 0;
vector<int>ans;
while (i <= n)
{
if (j == 0)i++, j++;
else if (isSame(nodes, i, nodet, j))
{
i++, j++;
if (j > m)--i, --j, ans.push_back(i - j + 1), j = next[j];
}
else j = next[j];
}
return ans;
}
private:
bool isSame(Node &nodes, int x, Node &nodet, int y)
{
int kx = nodes.p[x], ky = nodet.p[y];
return nodet.num[y][ky] == nodes.num[x][kx] - nodes.num[x - y][kx] &&
nodet.num[y][ky - 1] == nodes.num[x][kx - 1] - nodes.num[x - y][kx - 1];
}
vector<int> getNext(Node &nodet, int m) //m是串的长度
{
int i = 1, j = 0;
vector<int>next(m + 1);
next[0] = next[1] = 0;
while (i < m)
{
if (j == 0 || isSame(nodet, i, nodet, j))next[++i] = ++j;
else j = next[j];
}
return next;
}
private:
Node nodes, nodet;
};
2,测试代码
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 testStringOpt()//待完善
{
string s = "a{b{c}}d(e)f";
map<char, char>m;
m['{'] = '}';
m['('] = ')';
auto v = StringMatchSplit(s, m);
EXPECT_VEC_EQ(v[0], (vector<string>{"a", "d", "f"}));
EXPECT_VEC_EQ(v[1], (vector<string>{"b{c}", "e"}));
return true;
}
bool testRabinKarp()//待完善
{
RabinKarp{};
return true;
}
bool testLongestDupSubstring()//待完善
{
LongestDupSubstring{};
return true;
}
bool testKmp()//待完善
{
KMP<> opt;
return true;
}
bool testOrderMatch()//待完善
{
Node nod1, nod2;
OrderMatch opt(nod1, nod2);
return true;
}
int main()
{
if (testStringOpt() && testRabinKarp() && testLongestDupSubstring() && testKmp() && testOrderMatch())cout << "test succ!";
return 0;
}
四,几何
1,代码
struct Point
{
double x;
double y;
Point() { x = y = 0; }
Point(int x, int y) { this->x = x, this->y = y; }
Point(double x, double y) { this->x = x, this->y = y; }
bool operator<(const Point& p)const
{
if (x == p.x)return y < p.y;
return x < p.x;
}
};
struct Line
{
double a, b, c;//ax+by+c=0;
Line() { a = 1, b = c = 0; }
Line(double a, double b, double c) { this->a = a, this->b = b, this->c = c; }
Line(Point a, Point b) { //根据任意不同2点构造直线
this->a = b.y - a.y, this->b = a.x - b.x, this->c = a.y * b.x - a.x * b.y;
}
};
struct Polygon
{
vector<Point>v; //v.size()>=3,按照顺时针或逆时针依次排列
Polygon(){}
Polygon(const vector<Point>&v2) { v = v2; }
};
enum PosStatus
{
Separation, // 相离
PointTangency,
LineTangency,
Intersect
};
class GeometryBase {
public:
static double slope(Point p1, Point p2)//求2点斜率,x一定不同
{
return (p2.y - p1.y) / (p2.x - p1.x);
}
static double pointDistance(Point p1, Point p2)//求2点距离
{
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
static double inCircle(Point O, double r, Point p)//判断点是否在圆内
{
return pointDistance(O, p) <= r;
}
static bool isParallels(Line s, Line t)// 两直线是否平行
{
return sameValue(deltaLineAndLine(s, t), 0);
}
static bool isSameLine(Line s, Line t)// 两直线是否重叠
{
return isParallels(s, t) && s.a * t.c == s.c * t.a;
}
static Point intersectionLineAndLine(Line s, Line t)// 两直线交点,仅在不平行时才能调用
{
double delta = deltaLineAndLine(s, t);
return Point{ (t.c * s.b - s.c * t.b) / delta, (s.c * t.a - s.a * t.c) / delta };
}
static bool pointInSegment(Point s, Point e, Point p)//已知线段se和点p在一条直线上,判断p是否在se之间(包括se)
{
return (e.y - p.y)*(s.y - p.y) + (e.x - p.x)*(s.x - p.x) <= 0;
}
static bool isSameSide(Line s, Point p1, Point p2) //2点是否在直线同侧,包括点在直线上也算
{
return deltaPointAndLine(s, p1)*deltaPointAndLine(s, p2) >= 0;
}
static bool isPointInLine(Line s, Point p)//点是否在直线上
{
return deltaPointAndLine(s, p) == 0;
}
static PosStatus getPosStatus(Polygon p, Line s, vector<Point>&intersection) // 求凸多边形和直线的4种位置关系,如果相交则输出交点
{
bool flag = false;
auto &v = p.v;
vector<int>id, id2;
for (int i = 0; i < v.size(); i++) {
if (!isSameSide(s, v[i], v[(i+1)%v.size()])) {
flag = true;
id.push_back(i);
}
if (isPointInLine(s, v[i])) {
id2.push_back(i);
}
}
if (flag) {
for (int i: id) {
Line t(v[i], v[(i + 1) % v.size()]);
intersection.push_back(intersectionLineAndLine(s,t));
}
for (int i : id2)intersection.push_back(v[i]);
return PosStatus::Intersect;
}
if (id2.size() == 0)return PosStatus::Separation;
if (id2.size() == 1)return PosStatus::PointTangency;
if (id2[1] == id2[0] + 1 || id2[1] == id2[0] + v.size() - 1)return PosStatus::LineTangency;
for (int i : id2)intersection.push_back(v[i]);
return PosStatus::Intersect;
}
static double getMaxSlope(vector<Point>v)//求点集中任意两点斜率的最大值
{
if (v.size() < 2)return -DBL_MAX;
sort(v.begin(), v.end(), cmpPoint);
double ans = -DBL_MAX;
for (int i = 1; i < v.size(); i++) {
if (v[i].x == v[i - 1].x)continue;
ans = max(ans, (v[i].y - v[i - 1].y) / (v[i].x - v[i - 1].x));
}
return ans;
}
static double getMinSlope(vector<Point>v)//求点集中任意两点斜率的最小值
{
for (auto &vi : v)vi.y *= -1;
return -getMaxSlope(v);
}
protected:
static bool sameValue(double x, double y)
{
return abs(x - y) < 0.00001;
}
// 直线的判定式
static double deltaLineAndLine(Line s, Line t)
{
return s.a * t.b - s.b * t.a;
}
// 点对直线的判定式
static double deltaPointAndLine(Line s, Point p)
{
return s.a * p.x + s.b * p.y + s.c;
}
};
class Andrew :public GeometryBase //求凸包
{
public:
vector<Point>up, 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<Point> getAll() //push之后获取整个凸包,从左下到左上,逆时针
{
vector<Point>ans = 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:
static bool less(double x, double x2) {
return x < x2;
}
static bool lesseq(double x, double x2) {
return x <= x2;
}
vector<Point>lefts, rights;
bool flag;
};
class Geometry :public GeometryBase //几何
{
using T = int;
public:
Point minMaxWithSlope(vector<Point>& 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:
T find(T low, T high)
{
if (!isOk(high))return high + 1;
if (isOk(low))return low;
T mid;
while (high - low > 1) {
mid = (high + low) / 2;
if (isOk(mid))high = mid;
else low = mid;
}
return high;
}
virtual bool isOk(int x) const //若isOk(x)且!isOk(y)则必有y<x
{
return (type == "max") ? (slope(ps[x], ps[x + 1]) < k) : (slope(ps[x], ps[x + 1]) > k);
}
private:
string type;
vector<Point> ps;
double k;
};
2,测试代码
#define EXPECT_EQ(a,b) if(a!=b){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testGeometryBase()//待完善
{
return true;
}
bool testAndrewAndMinMaxWithSlope()
{
Andrew andrew;
andrew.push(Point{ 0,0 });
andrew.push(Point{ 1.0,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;
}
int main()
{
if (testGeometryBase() && testAndrewAndMinMaxWithSlope())cout << "test succ!";
return 0;
}
五,类型提升、数据结构转换、累积计算、动态规划
1,代码
#ifdef OLD_PLATFORM
#define UpperType(T) T
#else
template<typename T, bool flag>
struct enable {
typedef T type;
};
template<typename T>
struct enable<T, true> {
typedef long long type;
};
#define UpperType(T) typename enable<T, is_integral_v<T>>::type
#endif
class BasicOpt
{
public:
//把列表的每个元素进行p转换,p:T1->T2
template<typename T1, typename T2, typename Tfunc>
static vector<T2> vecTrans(const vector<T1>& v, Tfunc p)
{
vector<T2>v2;
transform(v.begin(), v.end(), std::back_inserter(v2), p);
return v2;
}
//把map的每个pair进行p转换,p:<T0,T1>->T2,自动变成<T0,T2>的pair
template<typename T0, typename T1, typename T2, typename Tfunc>
static map<T0, T2> mapTrans(const map<T0, T1>& m, Tfunc p)
{
map<T0, T2>m2;
transform(m.begin(), m.end(), std::inserter(m2, m2.end()), [&](const pair<T0, T1>& apair) {return make_pair(apair.first, p(apair)); });
return m2;
}
//把map的每个pair进行p转换,p:<T0,T1>->T2
template<typename T0, typename T1, typename T2, typename Tfunc>
static vector<T2> mapTransToVec(const map<T0, T1>& m, Tfunc p)
{
vector<T2>v;
transform(m.begin(), m.end(), std::back_inserter(v), p);
return v;
}
//把map转成pair数组
template<typename T1, typename T2>
static vector<pair<T1, T2>> mapToPairs(const map<T1, T2>& m)
{
return mapTransToVec<T1, T2, pair<T1, T2>>(m, [](const pair<T1, T2>& p) {return p; });
}
//提取pair数组的first
template<typename T1, typename T2>
static vector<T1> drawFirst(const vector<pair<T1, T2>>& v)
{
return vecTrans<pair<T1, T2>, T1>(v, [](const pair<T1, T2>& p) {return p.first; });
}
//提取pair数组的second
template<typename T1, typename T2>
static vector<T2> drawSecond(const vector<pair<T1, T2>>& v)
{
return vecTrans<pair<T1, T2>, T2>(v, [](const pair<T1, T2>& p) {return p.second; });
}
//提取map的first
template<typename T1, typename T2>
static vector<T1> getMapFirst(const map<T1, T2>& m)
{
return drawFirst(mapToPairs(m));
}
//提取map的second
template<typename T1, typename T2>
static vector<T2> getMapSecond(const map<T1, T2>& m)
{
return drawSecond(mapToPairs(m));
}
//栈转化成数组
template<typename T>
static vector<T> stackToVec(stack<T>q) //谨慎传引用
{
vector<T>v(q.size());
int id = q.size() - 1;
while (!q.empty())v[id--] = q.top(), q.pop();
return v;
}
//队列转化成数组
template<typename T>
static vector<T> queToVec(queue<T>q) //谨慎传引用
{
vector<T>v;
while (!q.empty())v.push_back(q.front()), q.pop();
return v;
}
//vector转数组
template<typename T>
static T* vecToArr(vector<T>& v)
{
return v.data();
}
//把id数组(一维或二维)转化为对应的数v[id]
template<typename T>
static vector<T> getNumFromId(const vector<T>& v, const vector<int>& id)
{
return vecTrans<int, T>(id, [&](int i) {return (i >= 0 && i < v.size()) ? v[i] : -1; });
}
template<typename T>
static vector<vector<T>> getNumFromId(const vector<T>& v, const vector<vector<int>>& id)
{
return vecTrans<vector<int>, vector<T>>(id, [&](const vector<int>& i) {return getNumFromId(v, i); });
}
//把v1和v2 匹配转化成1个map<v1,v2>
template<typename T1, typename T2>
static map<T1, T2> vectorToMap(const vector<T1>& v1, const vector<T2>& v2)
{
map<T1, T2>m;
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<typename T1, typename T2>
static vector<T2> vmToVector(const vector<T1>& v, map<T1, T2>& m)
{
vector<T2>ans;
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, *T>->T2
template<typename T, typename T2, typename Tfunc>
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<typename T>
static T getVecMax(const vector<T>& v)
{
return getMultiOpt<decltype(v.begin()), T>(v.begin(), v.end(), [](const T x1, const T x2) {return max(x1, x2); });
}
template<typename T>
static T getVecMax2(const vector<vector<T>>& v)
{
return getVecMax(vecTrans<vector<T>, T>(v, getVecMax<T>));
}
//获取vector中最小值
template<typename T>
static T getVecMin(const vector<T>& v)
{
return getMultiOpt<decltype(v.begin()), T>(v.begin(), v.end(), [](const T x1, const T x2) {return min(x1, x2); });
}
//获取二维vector中最小值
template<typename T>
static T getVecMin2(const vector<vector<T>>& v)
{
return getVecMin(vecTrans<vector<T>, T>(v, getVecMin<T>));
}
//获取所有元素之和
template<typename T>
static UpperType(T) getVecSum(const vector<T>& v)
{
return getMultiOpt<decltype(v.begin()), UpperType(T)>(v.begin(), v.end(), [](const T x1, const T x2) {return x1 + x2; });
}
//进行p转换并求和,返回p(v[0])+p(v[1])+...
template<typename T1, typename T2, typename Tfunc>
static T2 transSum(const vector<T1>& v, Tfunc p)
{
return getVecSum(vecTrans<T1, T2, Tfunc>(v, p));
}
//计算二维列表的元素数
template<typename T>
static int numInVec2D(const vector<vector<T>>& v)
{
return transSum<vector<T>, int>(v, [&](const vector<T>& v) {return v.size(); });
}
};
template<typename T = int, typename T2 = int>
class ArrayDP
{
protected:
ArrayDP(const vector<T>&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{};
vector<T>data;
vector<T2>ans;
};
class DP_LengthOfLIS :public ArrayDP<int, pair<int, int>>
{
public:
DP_LengthOfLIS(const vector<int>&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<int, unordered_map<int, int>>
{
public:
DP_lengthOfEqualDif(const vector<int>&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<typename T>
static vector<T> maxSubArrayFromEver(const vector<T>& v)
{
vector<T>ans = v;
for (int i = v.size() - 2; i >= 0; i--) {
if (ans[i + 1] > 0)ans[i] += ans[i + 1];
}
return ans;
}
//求最大子段和
template<typename T>
static T maxSubArray(const vector<T>& v)
{
return getVecMax(maxSubArrayFromEver(v));
}
};
2,测试代码
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 testBasicOpt()//待完善
{
map<int, char>m;
m[2] = '4', m[6] = '9';
return true;
}
bool testMultiOpt()
{
vector<int>v{ 1,2,3,5,7 };
EXPECT_EQ(GetVecMax(v), 7);
vector<vector<int>>v2{ {2,4},{3,1,5} };
EXPECT_EQ(GetVecMin2(v2), 1);
EXPECT_EQ(GetVecSum(v), 18);
EXPECT_EQ(NumInVec2D(v2), 5);
}
bool testDP()//待完善
{
vector<int>v{ 1,2,3,5,7 };
MaxSubArray(v);
EXPECT_EQ(DP_lengthOfEqualDif(v).getLength(), 4);
}
int main()
{
if (testBasicOpt() && testMultiOpt() && testDP())cout << "test succ!";
return 0;
}