版权声明:转载请附带原文链接,请勿随意删除原文内容,允许少量格式和/或内容修改,谢谢! 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
。