ACM模板三:二分、字典树、字符串、几何、DP

目录

〇,全文说明、宏定义代码

一,二分查找

1,代码

2,测试代码

二,类型计算、字典树

1,代码

2,测试代码

三,字符串处理、串匹配

1,代码

2,测试代码

四,几何

1,代码

2,测试代码

五,类型提升、数据结构转换、累积计算、动态规划

1,代码

2,测试代码


〇,全文说明、宏定义代码

类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。

代码工程结构:

  • 每一章的第一节《代码》可以独立编译运行(本地要加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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值