ACM模板(字符串、组合、代数、几何)

目录

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

一,类型计算、二分查找、字典树、字符串处理、几何

二,排列组合

三,代数

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

五,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;
	}
};

五,test

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;
}

你可能感兴趣的:(java,开发语言)