学习笔记:OI常用模板(二)

版权声明:转载请附带原文链接,请勿随意删除原文内容,允许少量格式和/或内容修改,谢谢! https://blog.csdn.net/weixin_37661548/article/details/88569756

最小瓶颈路

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005,MAXM = 100005;

struct edge
{
	int to,nxt,wgt;
}info[MAXM << 1];

struct input
{
	int from,to,wgt;
	friend bool operator < (const input &opa,const input &opb)
	{
		return opa.wgt < opb.wgt;
	}
}tmp[MAXM];

int n,m,k,e,ui,vi,wi,mst;
int head[MAXN],f[MAXN],dep[MAXN],fa[MAXN][20],maxPath[MAXN][20],lg[MAXN];

void dfs(int u,int f,int d)
{
	fa[u][0] = f;
	dep[u] = d;
	for (int i = 1;i <= lg[d];++i)
	{
		fa[u][i] = fa[fa[u][i - 1]][i - 1];
		maxPath[u][i] = max(maxPath[u][i - 1],maxPath[fa[u][i - 1]][i - 1]);
	}
	for (int i = head[u];i;i = info[i].nxt)
	{
		int v = info[i].to;
		if (v == f) continue;
		maxPath[v][0] = info[i].wgt;
		dfs(v,u,d + 1);
	}
}

int LCA(int u,int v)
{
	if (dep[u] < dep[v]) swap(u,v);
	while (dep[u] != dep[v]) u = fa[u][lg[dep[u] - dep[v]]];
	if (u == v) return u;
	for (int i = lg[dep[u]];i >= 0;--i)
	{
		if (fa[u][i] != fa[v][i])
		{
			u = fa[u][i];
			v = fa[v][i];
		}
	}
	return fa[u][0];
}

int find(int opa)
{
	return f[opa] == opa ? opa : f[opa] = find(f[opa]);
}

inline void merge(int opa,int opb)
{
	f[find(opa)] = find(opb);
}

void kruskal()
{
	int cnt = 0;
	for (int i = 1;i <= m;++i)
	{
		int u = tmp[i].from;
		int v = tmp[i].to;
		int w = tmp[i].wgt;
		if (find(u) == find(v)) continue;
		merge(u,v);
		addedge(u,v,w);
		addedge(v,u,w);
		mst += w;
		cnt++;
	}
}

int calc(int u,int v,int lca)
{
	int res = -0x3f3f3f3f;
	while (dep[u] != dep[lca])
	{
		res = max(res,maxPath[u][lg[dep[u] - dep[lca]]]);
		u = fa[u][lg[dep[u] - dep[lca]]];
	}
	while (dep[v] != dep[lca])
	{
		res = max(res,maxPath[v][lg[dep[v] - dep[lca]]]);
		v = fa[v][lg[dep[v] - dep[lca]]];
	}
	return res;
}

void init()
{
	freopen("in.txt","r",stdin);
	scanf("%d%d%d",&n,&m,&k);
	for (int i = 1;i <= m;++i)
	{
		qread(tmp[i].from);
		qread(tmp[i].to);
		qread(tmp[i].wgt);
	}
	sort(tmp + 1,tmp + m + 1);
	lg[0] = -1;
	for (int i = 1;i <= n;++i)
	{
		lg[i] = lg[i >> 1] + 1;
		f[i] = i;
	}
}

void work()
{
	kruskal();
	dfs(1,0,0);
	for (int i = 1;i <= k;++i)
	{
		qread(ui);
		qread(vi);
		if (find(ui) != find(vi))
		{
			printf("-1\n");
			continue;
		}
		int lca = LCA(ui,vi);
		int ans = calc(ui,vi,lca);
		qwrite(ans);
		putchar('\n');
	}
}

次小生成树 严格次小生成树

洛谷 P4180 【模板】严格次小生成树[BJWC2010]

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005,MAXM = 300005;

...

struct input
{
	int from,to,wgt;
	bool mark;
	friend bool operator < (const input &opa,const input &opb)
	{
		return opa.wgt < opb.wgt;
	}
}tmp[MAXM];

long long mst,smst,ans = LLONG_MAX;
int n,m,e,ui,vi,wi,Max,Sec;
int head[MAXN];

...

namespace Kruskal
{
	int f[MAXN];
	
	int find(int x)
	{
		return f[x] == x ? x : f[x] = find(f[x]);
	}
	
	void merge(int u,int v)
	{
		f[find(u)] = find(v);
	}
	
	void kruskal()
	{
		int cnt = 0;
		for (int i = 1;i <= m;++i)
		{
			if (cnt == n - 1) break;
			int u = tmp[i].from;
			int v = tmp[i].to;
			int w = tmp[i].wgt;
			if (find(u) == find(v)) continue;
			merge(u,v);
			addedge(u,v,w);
			addedge(v,u,w);
			tmp[i].mark = true;
			mst += w, cnt++;
		}
	}
}
using namespace Kruskal;

namespace LowestCommonAncestor
{
	int dep[MAXN],fa[MAXN][20],maxPath[MAXN][20],secPath[MAXN][20],lg[MAXN];
	
	void dfs(int u,int f,int d)
	{
		fa[u][0] = f, dep[u] = d;
		for (int i = 1;i <= lg[d];++i)
		{
			fa[u][i] = fa[fa[u][i - 1]][i - 1];
			int t = fa[u][i - 1];
			if (maxPath[u][i - 1] < maxPath[t][i - 1]) secPath[u][i] = max(maxPath[u][i - 1],secPath[t][i - 1]);
			if (maxPath[u][i - 1] > maxPath[t][i - 1]) secPath[u][i] = max(maxPath[t][i - 1],secPath[t][i - 1]);
			if (maxPath[u][i - 1] == maxPath[t][i - 1]) secPath[u][i] = max(secPath[u][i - 1],secPath[t][i - 1]);
			maxPath[u][i] = max(maxPath[u][i - 1],maxPath[t][i - 1]);
		}
		for (int i = head[u];i;i = info[i].nxt)
		{
			int v = info[i].to;
			int w = info[i].wgt;
			if (v == f) continue;
			maxPath[v][0] = w;
			secPath[v][0] = -INT_MAX;
			dfs(v,u,d + 1);
		}
	}
	
	int LCA(int u,int v)
	{
		if (dep[u] < dep[v]) swap(u,v);
		while (dep[u] != dep[v]) u = fa[u][lg[dep[u] - dep[v]]];
		if (u == v) return u;
		for (int i = lg[dep[u]];i >= 0;--i)
		{
			if (fa[u][i] != fa[v][i])
			{
				u = fa[u][i];
				v = fa[v][i];
			}
		}
		return fa[u][0];
	}
}
using namespace LowestCommonAncestor;

void calc(int u,int v,int lca)
{
	Max = Sec = -INT_MAX;
	while (dep[u] != dep[lca])
	{
		int pathMax = maxPath[u][lg[dep[u] - dep[lca]]];
		int pathSec = secPath[u][lg[dep[u] - dep[lca]]];
		if (pathMax > Max) Sec = max(Max,pathSec);
		if (pathMax < Max) Sec = max(Sec,pathMax);
		if (Max == pathMax) Sec = max(Sec,pathSec);
		Max = max(Max,pathMax);
		u = fa[u][lg[dep[u] - dep[lca]]];
	}
	while (dep[v] != dep[lca])
	{
		int pathMax = maxPath[v][lg[dep[v] - dep[lca]]];
		int pathSec = secPath[v][lg[dep[v] - dep[lca]]];
		if (pathMax > Max) Sec = max(Max,pathSec);
		if (Max > pathMax) Sec = max(Sec,pathMax);
		if (Max == pathMax) Sec = max(Sec,pathSec);
		Max = max(Max,pathMax);
		v = fa[v][lg[dep[v] - dep[lca]]];
	}
}

void init()
{
	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&m);
	for (int i = 1;i <= m;++i)
	{
		qread(tmp[i].from);
		qread(tmp[i].to);
		qread(tmp[i].wgt);
		tmp[i].mark = false;
	}
	sort(tmp + 1,tmp + m + 1);
	lg[0] = -1;
	for (int i = 1;i <= n;++i)
	{
		lg[i] = lg[i >> 1] + 1;
		f[i] = i;
	}
}

void work()
{
	kruskal();
	dfs(1,0,0);
	for (int i = 1;i <= m;++i)
	{
		if (tmp[i].mark == true) continue;
		int u = tmp[i].from;
		int v = tmp[i].to;
		int w = tmp[i].wgt;
		int lca = LCA(u,v);
		calc(u,v,lca);
		if (w > Max)
		{
			smst = mst + w - Max;
			if (smst > mst) ans = min(smst,ans);
		}
		else if (w == Max && Sec != -INT_MAX)
		{
			smst = mst + w - Sec;
			if (smst > mst) ans = min(smst,ans);
		}
		else continue;
	}
	qwrite(ans);
}

主席树 / 可持久化线段树

洛谷 P3834 【模板】可持久化线段树 1(主席树)

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 200005;

int n,m,li,ri,ki,length,nid;
//初始数字个数;询问个数;询问左右区间;第k大的数;离散化后数列长度;所有线段树的所有节点的序号。
int a[MAXN],b[MAXN];
//原数列和离散化后的数列。
int Root[MAXN * 40],lson[MAXN * 40],rson[MAXN * 40],sum[MAXN * 40];
//主席树(Root[]数组)的每一个节点(数组元素)都是一棵线段树的根节点(代表1~n的区间)。
//一般而言,主席树要开40倍的数组。

...

namespace ChairmanTree
{
	void buildTree(int l,int r,int &cur) //使用引用传递参数,得以给每个节点编号。
	{
		cur = ++nid;
		sum[cur] = 0;
		if (l == r) return; //已经到达叶子节点,返回。注意这句话要写在上面的初始化下面。
		int mid = (l + r) >> 1;
		buildTree(l,mid,lson[cur]); //相同子问题。
		buildTree(mid + 1,r,rson[cur]);
	}
	
	inline void update(int l,int r,int &cur,int pre,int pos)
	{
		cur = ++nid;
		lson[cur] = lson[pre];
		rson[cur] = rson[pre]; //初始化,之后左右子节点的标号可能被修改。
		sum[cur] = sum[pre] + 1; //加入了一个新数,那么这个数所在的区间sum值就要增加。
		if (l == r) return;
		int mid = (l + r) >> 1;
		if (pos <= mid) update(l,mid,lson[cur],lson[pre],pos);
		else update(mid + 1,r,rson[cur],rson[pre],pos);
		//假如执行了else语句,看起来rson[cur]和rson[pre]是一样的,但进入
		//下一层递归后,rson[cur]就变成了++nid,就是相当于新开了一个节点。
	}
	
	inline int query(int L,int R,int l,int r,int k)
	{
		if (l == r) return l;
		int mid = (l + r) >> 1;
		int lcnt = sum[lson[R]] - sum[lson[L]]; //统计左子树的数字个数。假如要问区间第4大,左子树
												//一共只有3个数,那么这个第4大就一定在右子树了。
		if (k <= lcnt) return query(lson[L],lson[R],l,mid,k);
		else return query(rson[L],rson[R],mid + 1,r,k - lcnt); //是k - lcnt不是k.
	}
}
using namespace ChairmanTree;

void init()
{
	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&m);
	for (int i = 1;i <= n;++i)
	{
		qread(a[i]);
		b[i] = a[i];
	}
	sort(b + 1,b + n + 1); //数组是1基准的。
	length = unique(b + 1,b + n + 1) - (b + 1);
	buildTree(1,length,Root[0]);
	for (int i = 1;i <= n;++i)
	{
		a[i] = lower_bound(b + 1,b + length + 1,a[i]) - b;
		//lower_bound()返回的是迭代器,还要减去b数组首地址来得到元素下标。
		//由于这里是对离散化后的b数组操作,b数组的右界应是b + length + 1而不是b + n + 1
	}
	for (int i = 1;i <= n;++i)
		update(1,length,Root[i],Root[i - 1],a[i]);
}

void work()
{
	for (int i = 1;i <= m;++i)
	{
		qread(li);
		qread(ri);
		qread(ki);
		int ans = query(Root[li - 1],Root[ri],1,length,ki);
		printf("%d\n",b[ans]); //ans是离散化后的位置,要得到离散化前的值就要写成b[ans].
	}
}

网络流 网络最大流

洛谷 P3376 【模板】网络最大流

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 10005,MAXM = 100005,INF = 0x3f3f3f3f;

struct edge
{
	int to,nxt,wgt;
}info[MAXM << 1];

int n,m,S,T,e,ui,vi,wi,ans;
int head[MAXN],dep[MAXN],curArc[MAXN];
queue<int> Q;

...

void init()
{
	...
	for (int i = 1;i <= m;++i)
	{
		qread(ui);
		qread(vi);
		qread(wi);
		addedge(ui,vi,wi);
		addedge(vi,ui,0);
	}
}

inline bool bfs()
{
	for (int i = 1;i <= n;++i) dep[i] = -1;
	dep[S] = 0;
	Q.push(S);
	while (!Q.empty())
	{
		int u = Q.front();
		Q.pop();
		for (int i = head[u];i != -1;i = info[i].nxt)
		{
			int v = info[i].to;
			if (dep[v] == -1 && info[i].wgt > 0)
			{
				dep[v] = dep[u] + 1;
				Q.push(v);
			}
		}
	}
	return dep[T] != -1;
}

inline int dfs(int u,int capacity)
{
	if (u == T) return capacity;
	int used = 0;
	for (int i = curArc[u];i != -1;i = info[i].nxt)
	{
		curArc[u] = i;
		int v = info[i].to;
		if (dep[v] == dep[u] + 1 && info[i].wgt > 0)
		{
			int d = dfs(v,min(capacity - used,info[i].wgt));
			info[i].wgt -= d;
			info[i ^ 1].wgt += d;
			used += d;
			if (used == capacity) break;
		}
	}
	return used;
}

void dinic()
{
	while (bfs())
	{
		for (int i = 1;i <= n;++i)
		{
			curArc[i] = head[i];
		}
		ans += dfs(S,INF);
	}
}

void work()
{
	dinic();
	printf("%d",ans);
}

网络流 最小费用最大流

洛谷 P3381 【模板】最小费用最大流

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 5005,MAXM = 50005;

struct edge
{
	int to,nxt,flow,cost;//flow:该边残量。
}info[MAXM << 1];

int n,m,s,t,e,ui,vi,wi,fi;
int head[MAXN];

template<typename T> void qread(T &sum)
{
	sum = 0;
	register int sym = 1;
	register char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-') sym = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		sum = (sum << 1) + (sum << 3) + ch - '0';
		ch = getchar();
	}
	sum *= sym;
}

template<typename T> T mmin(const T &x,const T &y)
{
	if (x > y) return y;
	else return x;
}

namespace MinCostMaxFlow
{
	int maxflow,mincost;
	int dis[MAXN],vis[MAXN],flow[MAXN],last[MAXN],pre[MAXN];
	//这里把每条边的单位费用当作权值来跑spfa。dis就是源点到汇点经过所有边的单位费用和。
	//flow就是从源点到该点的流量。last:当前节点的上条边。pre:当前节点的前驱节点。
	queue<int> Q;
	
	bool spfa(int S,int T)
	{
		memset(dis,0x3f,sizeof(dis));
		memset(flow,0x3f,sizeof(flow));
		memset(vis,false,sizeof(vis));
		dis[S] = 0;
		pre[T] = -1;
		Q.push(s);
		vis[S] = true;
		while (!Q.empty())
		{
			int u = Q.front();
			Q.pop();
			vis[u] = false;
			for (int i = head[u];i != -1;i = info[i].nxt)
			{
				int v = info[i].to;
				if (info[i].flow > 0 && dis[v] > dis[u] + info[i].cost)
				{
					dis[v] = dis[u] + info[i].cost;
					flow[v] = mmin(flow[u],info[i].flow);
					pre[v] = u;
					last[v] = i;
					if (!vis[v])
					{
						Q.push(v);
						vis[v] = true;
					}
				}
			}
		}
		return pre[T] != -1;
	}
}
using namespace MinCostMaxFlow;

inline void addedge(int from,int to,int flow,int cost)
{
	info[e].to = to;
	info[e].flow = flow;
	info[e].cost = cost;
	info[e].nxt = head[from];
	head[from] = e++;
}

void init()
{
	freopen("in.txt","r",stdin);
	memset(head,-1,sizeof(head));
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for (int i = 1;i <= m;++i)
	{
		qread(ui);
		qread(vi);
		qread(wi);
		qread(fi);
		addedge(ui,vi,wi,fi);
		addedge(vi,ui,0,-fi);
	}
}

void work()
{
	while (spfa(s,t))
	{
		int cur = t;
		maxflow += flow[t];
		mincost += flow[t] * dis[t];
		while (cur != s)
		{
			info[last[cur]].flow -= flow[t];
			info[last[cur] ^ 1].flow += flow[t];
			cur = pre[cur];
		}
	}
	printf("%d %d",maxflow,mincost);
}

int main()
{
	init();
	work();
	return 0;
}

模拟退火

洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;
const long double D = 0.993,T = 100000,EPS = 1E-15;

long double n,bestX,bestY,best,ans;
long double position[MAXN][2],weight[MAXN];
//当心卡精度。保险起见开long double.

inline long double calcDist(long double x,long double y)
{
	long double result = 0;
	for (int i = 1;i <= n;i++)
		result += weight[i] * sqrt(pow(position[i][0] - x,2) + pow(position[i][1] - y,2));
	return result;
}

inline long double randMove(long double t)
{
	return t * ((rand() << 1) - RAND_MAX);
}

void init()
{
	freopen("in.txt","r",stdin);
	scanf("%LF",&n);
	for (int i = 1;i <= n;i++)
	{
		scanf("%LF%LF%LF",&position[i][0],&position[i][1],&weight[i]);
		bestX += position[i][0];
		bestY += position[i][1];
	}
	srand(20190128);
	best = ans = calcDist(bestX /= n, bestY /= n);
}

void stimulatedAnneling()
{
	long double curX,curY,nextX,nextY,res;
	curX = bestX;
	curY = bestY;
	for (long double t = T;t >= EPS;t *= D)
	{
		nextX = curX + randMove(t);
		nextY = curY + randMove(t);
		res = calcDist(nextX,nextY);
		if (res < best)
		{
			best = res;
			bestX = nextX;
			bestY = nextY;
		}
		if (res < ans || exp((ans - res) / t) * (long double)RAND_MAX > rand())
		{
			ans = res;
			curX = nextX;
			curY = nextY;
		}
	}
}

void work()
{
	stimulatedAnneling();
	printf("%.3Lf %.3Lf",bestX,bestY);
}

字符串匹配 KMP

洛谷 P3375 【模板】KMP字符串匹配

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1000005;

char text[MAXN],pattern[MAXN];
int prefix[MAXN];
int text_size,pattern_size;
bool state;

void make_prefix()
{
	int i = 0,j = -1;
	while (i < text_size)
	{
		if (j == -1 || pattern[i] == pattern[j]) prefix[++i] = ++j;
		else j = prefix[j];
	}
}

void init()
{
	freopen("in.txt","r",stdin);
	scanf("%s%s",text,pattern);
	text_size = strlen(text);
	pattern_size = strlen(pattern);
	prefix[0] = -1;
	make_prefix();
}

void work()
{
	int i = 0,j = 0;
	while (i < text_size)
	{
		if (j == -1 || text[i] == pattern[j]) {i++; j++;}
		else j = prefix[j];
		if (j == pattern_size) {state = true; printf("%d\n",i - j + 1);}
	}
	if (!state) printf("-1");
	for (int i = 1;i <= pattern_size;i++) printf("%d ",prefix[i]);
}

D.E.Knuth、J.H.Morris 和 V.R.Pratt。


字符串匹配 AC自动机

洛谷 P3808 【模板】AC自动机(简单版)

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 10006;

int T,n,cnt;
char text[MAXN],pattern[MAXN];
queue<int> Q;

namespace Aho_Corasick_Automaton
{
	int trie[MAXN][26],fail[MAXN],isword[MAXN];

	void insert(char arr[])
	{
		int len = strlen(arr),root = 0,id = 0;
		for (int i = 0;i < len;i++)
		{
			id = arr[i] - 'a';
			if (trie[root][id] == 0) trie[root][id] = ++cnt;
			root = trie[root][id];
		}
		isword[root]++;
	}

	void build()
	{
		for (int i = 0;i < 26;i++)
			if (trie[0][i] != 0)
			{
				fail[trie[0][i]] = 0;
				Q.push(trie[0][i]);
			}
		while (!Q.empty())
		{
			int root = Q.front();
			Q.pop();
			for (int i = 0;i < 26;i++)
			{
				if (trie[root][i] != 0)
				{
					fail[trie[root][i]] = trie[fail[root]][i];
					Q.push(trie[root][i]);
				}
				else trie[root][i] = trie[fail[root]][i];
			}
		}
	}

	int query(char arr[])
	{
		int len = strlen(arr),root = 0,id = 0,ans = 0;
		for (int i = 0;i < len;i++)
		{
			id = arr[i] - 'a';
			root = trie[root][id];
			for (int j = root;j && (isword[j] != -1);j = fail[j])
			{
				ans += isword[j];
				isword[j] = -1;
			}
		}
		return ans;
	}
}
using namespace Aho_Corasick_Automaton;

void init()
{
	freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for (int i = 1;i <= n;i++)
	{
		scanf("%s",pattern);
		insert(pattern);
	}
	scanf("%s",text);
}

int main()
{
	init();
	build();
	printf("%d\n",query(text));
	return 0;
}

线段树

洛谷 P3372 【模板】线段树 1
参见上述:Splay 普通平衡树、树链剖分 朴素树链剖分。


树状数组

洛谷 P3374 【模板】树状数组 1

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 500005;

int n,m,q;
int c[MAXN];

inline int lowbit(int num)
{
	return num & (-num);
}

inline void add(int op,int delta)
{
	while (op <= n)
	{
		c[op] += delta;
		op += lowbit(op);
	}
}

inline int query(int op)
{
	int ans = 0;
	while (op > 0)
	{
		ans += c[op];
		op -= lowbit(op);
	}
	return ans;
}

int main()
{
	freopen("in.txt","r",stdin);
	qread(n);
	qread(m);
	for (int i = 1;i <= n;i++)
	{
		int tmp = 0;
		qread(tmp);
		add(i,tmp);
	}
	for (int i = 1;i <= m;i++)
	{
		qread(q);
		switch (q)
		{
			case 1 :
				{
					int index,delta;
					qread(index);
					qread(delta);
					add(index,delta);
					break;
				}
			case 2 :
				{
					int l,r;
					qread(l);
					qread(r);
					printf("%d\n",query(r) - query(l - 1));
					break;
				}
		}
	}
	return 0;
}

快速幂 整数快速幂

#include <cstdio>

int main()
{
	int a,b;
	scanf("%d%d",&a,&b);
	int ans = 1,base = a;
	while (b != 0)
	{
		if ((b & 1) != 0) ans *= base;
		base *= base;
		b >>= 1;
	}
	printf("%d",ans);
	return 0;
}

快速幂 矩阵快速幂

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 105,MOD = 1E9 + 7;

struct matrix
{
    long long m[MAXN][MAXN];
}text,temp,base,ans;

long long n,k;

matrix mat_mult(matrix opa,matrix opb)
{
    memset(temp.m,0,sizeof(temp.m));
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= n;j++)
            for (int k = 1;k <= n;k++)
                temp.m[i][j] = temp.m[i][j] % MOD + opa.m[i][k] * opb.m[k][j] % MOD;
    return temp;
}

void init()
{
    scanf("%lld%lld",&n,&k);
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= n;j++)
            scanf("%lld",&text.m[i][j]);
}

void work()
{
    for (int i = 1;i <= n;i++) ans.m[i][i] = 1;
    base = text;
    while (k)
    {
        if (k & 1) ans = mat_mult(ans,base);
        base = mat_mult(base,base);
        k >>= 1;
    }
    for (int i = 1;i <= n;i++)
    {
        for (int j = 1;j <= n;j++)
            printf("%lld ",ans.m[i][j] % MOD);
        printf("\n");
    }
}

Manacher

洛谷 P3805 【模板】manacher算法

...
const int MAXN = 150000;

int ans,k = 1,lena,lenb,id,rbound;
//答案;一个标记;初始字符串长度;处理后字符串长度;右界最右的回文子串的回文中心;最右的右界。
int p[MAXN << 1];
//以每个字符为回文中心的最大回文子串的半径。!!注意开两倍。
char input[MAXN],ops[MAXN << 1];
//初始字符串;处理后字符串。

void init()
{
	scanf("%s",input);
	lena = strlen(input);
	ops[0] = '>';
	for (int i = 0;i < lena;++i)//!!从0开始。
	{
		ops[k++] = '|';
		ops[k++] = input[i];
	}
	ops[k++] = '|';//勿忘。
	lenb = strlen(ops);
}

void work()
{
	for (int i = 1;i < lenb;++i) p[i] = min(p[(id << 1) - i],rbound - i);
	{
		if (i < rbound)
		//利用回文串的对称性,如果字符i在某个大回文串里,那么在这个大回文串的回文中心
		//的另一侧就会有一个和字符i一模一样的字符j。那么同样的,在整个大回文串范围内,
		//p[i]和p[j]值是一样的。
		
		//上面是对于p[j] <= rbound - i的情形。如果p[j] > rbound - i,那么以i和j为回
		//文中心的回文串在大回文串范围外的部分是否相等,就不知道了。所以要取两者中较小值。
		//(id << 1) - i就是两点中点公式变形移项后的结果。
		else p[i] = 1;//如果字符i不在某个大回文串里,只好从1开始向两边搜索。
		while (ops[i - p[i]] == ops[i + p[i]]) p[i]++;//搜索的过程。
		if (i + p[i] > rbound)//就是扩展最右的右界。
		{
			rbound = i + p[i];
			id = i;//记录右界最右的回文子串的回文中心。
		}
		if (p[i] > ans) ans = p[i];
	}
	printf("%d",ans - 1);
}

扩展欧几里德

洛谷 P1082 同余方程

//ax + by = 1
template<typename T> void exgcd(T a,T b,T &d,T &x,T &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		d = a;
	}
	else
	{
		exgcd(b,a % b,d,y,x);
		y -= (a / b) * x;
	}
}

/*
通解:
x = x0 + kb
y = y0 + kb
k ∈ R
*/

本题要求x大于0,答案为(x % b + b) % b

猜你喜欢

转载自blog.csdn.net/weixin_37661548/article/details/88569756
今日推荐