ACM 模板

template<class T> inline void rd(T &x)
{
    x=0;char o,f=1;
    while(o=getchar(),o<48)if(o==45)f=-f;
    do x=(x<<3)+(x<<1)+(o^48);
    while(o=getchar(),o>47);
    x*=f;
}

数论

快速幂

typedef long long ll;
ll quickpow(ll a,ll n,ll p) //a^n%p;
{
	ll ans = 1;
	while(n)
	{
		if(n&1) ans = ans * a % p;
		a = a * a %p;
		n >>= 1;
	}
	return ans;
}

欧几里得

int gcd(int a,int b)
{
	if(b==0)return a;
	return gcd(b,a%b);
}
int lcm(int a,int b)
{
	return a/gcd(a,b)*b;
}

扩展欧几里得

(1)求解不定方程;
(2)求解模线性方程(线性同余方程);
(3)求解模的逆元;

int exgcd(int a,int b,int &x,int &y)
{
	if(b==0) {
		x = 1;
		y = 0;
		return a;
	}
	int r = exgcd(b,a%b,x,y);
	int t = x;
	x = y;
	y = t-a/b*y;
	return r;
}

最小生成树

·prim

const int maxn = 505;
const int INF = 0x3f3f3f3f;
bool vis[maxn];
int lowc[maxn];
int cost[maxn][maxn];
int prim()
{
	int asn = 0;
	memset(vis,false,sizeof(vis));
	vis[0] = true;
	for(int i = 1;i < n;i++) lowc[i] = cost[0][i];
	for(int i = 1;i < n;i++)
	{
		int minc = INF;
		int p = -1;
		for(int j = 0;j < n;j++)
			if(!vis[j]&&minc > low[j])
			{
				minc = lowc[j];
				p = j;
			}
		if(minc == INF) return -1;
		ans+=minc;
		for(int j = 0;j < n;j++)
			if(!vis[j]&&lowc[j]>cost[p][j])
				lowc[j] = cost[p][j];
	}
	return ans;
}

最短路径

· 单源最短路径 迪杰斯特拉 Dijkstra

堆优化

const int maxn = 505;
vector<pair<int,int> > E[maxn];
priority_queue<pair<int,int> > q;
int pre[maxn];
bool vis[maxn];
int dis[maxn];
int s,d;//s为开始节点.
void dijkstar()
{
	dis[s] = 0;
	q.push(make_pair(-dis[s],s));
	while(!q.empty())
	{
		int t = q.top().second;
		q.pop();
		if(vis[t])
			continue;
		vis[t] = true;
		for(int i = 0;i < E[t].size();i++)
		{
			int to = E[t][i].first;
			int di = E[t][i].second;
			if(dis[to] > dis[t]+di)
			{
				dis[to] = dis[t]+di;
				pre[to] = t;
				q.push(make_pair(-dis[to],to);
			}
		}
	}
}

强连通分量

·Tarjan

const int maxn = 5e5+5;
vector<int> ep[maxn];
vector<int> bel[maxn];
stack<int> s;
int cnt,cntb;
int dfn[maxn];
int low[maxn];
int belong[maxn];
int out[maxn];
bool in_stack[maxn];
void Tarjan(int u)
{
	dfn[u] = low[u] = ++cnt;
	s.push(u);
	in_stack[u] = true;
	for(int i = 0;i < ep[u].size();i++)
	{
		int v = ep[u][i];
		if(!dfn[v])
		{
			Tarjan(v);
			low[u] = min(low[u],low[v]);
		}
		else if(in_stack[v])
				low[u] = min(low[u],dfn[v]);
	}
	if(dfn[u] == low[u])
	{
		++cntb;
		int node;
		do
		{
			node = s.top();
			s.pop();
			in_stack[node] = false;
			belong[node] = cntb;
			bel[cntb].push_back(node);
		}while(node!=u);
	}
}

·Kosaraju

·树状数组

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5+5;
int c[maxn];
int a[maxn];
int n;
int lowbit(int x)
{
    return x&(-x);
}
void Update(int i,int k)//在i位置上的值加k
{
    while(i<=n)
    {
        c[i]+=k,i+=lowbit(i);
    }
}
int sum(int x)//求a[1...x]的和
{
    int ret=0;
    while(x)
    {
        ret+=c[x],x-=lowbit(x);
    }
    return  ret;
}
int main()
{
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        cin >> a[i];
        Update(i,a[i]);
    }
    cout << sum(n)<<endl;
    return 0;
}

Manacher

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e3+5;

int p[maxn*2];

string Manacher(string s)
{
    string t= "$#";
    for(int i = 0;i < s.size();i++)
    {
        t+=s[i];
        t+="#";
    }
    int mx = 0,id=0,reslen=0,rescenter=0;
    for(int i =1;i < t.size();i++)
    {
        p[i]=mx>id?min(p[2*id-i],mx-i):1;
        while(t[i+p[i]]==t[i-p[i]])p[i]++;
        if(i+p[i]>mx)
        {
            mx=i+p[i];
            id=i;
        }
        if(p[i]>reslen)
        {
            reslen=p[i];
            rescenter=i;
        }

    }
    return s.substr((rescenter-reslen)/2,reslen-1);
}
int main()
{
    string s;
    getline(cin,s);
    string t = Manacher(s);
    cout << t.size()<<endl;
    return 0;
}

线段树

//#include <bits/stdc++.h>
//
//using namespace std;
//const int maxn = 1e5+5;
//typedef long long ll;
//typedef unsigned long long ull;
//struct node{
//    ll sum,lazy;
//};
//int n,m;
//int a[maxn];
//node t[4*maxn];
//void change(int x,int tl,int tr,int p,int k)//单点修改p位置加k
//{
//    if(tl==tr)
//    {
//        t[x].sum+=k;
//        return;
//    }
//    int mid = (tl+tr)>>1;
//    if(p<=mid)change(2*x,tl,mid,p,k);
//    else change(2*x+1,mid+1,r,p,k);
//    t[x].sum=t[2*x].sum+t[2*x+1].sum;
//}
//void update(int x,int tl,int tr)
//{
//    t[x].sum = t[x].sum+(tr-tl+1)*t[x].lazy;
//    if(tl!=tr)
//    {
//        t[2*x].lazy+=t[x].lazy;
//        t[2*x+1].lazy+=t[x].lazy;
//    }
//    t[x].lazy=0;
//}
//void change(int x,int tl,int tr,int l,int r,int k)
//{
//    if(tl==l&&tr==r)
//    {
//        t[x].lazy+=k;
//        return;
//    }
//    if(t[x].lazy)update(x,tl,tr);
//    int mid = (tl+tr)>>1;
//    if(r<=mid)change(2*x,tl,mid,l,r,k);
//    else if(l>mid)change(2*x+1,mid+1,tr,l,r,k);
//    else{
//        change(2*x,tl,mid,l,mid,k);
//        change(2*x+1,mid+1,tr,mid+1,r,k);
//    }
//    t[x].sum=t[2*x].sum+(mid-tl+1)*t[2*x].lazy+t[2*x+1].sum+(tr-mid)*t[2*x+1].lazy;
//}
//ll ask(int x,int tl,int tr,int l,int r)//查询[l,r]的和
//{
//    if(tl==l&&tr==r) return t[x].sum;
//    int mid = (tl+tr)>>1;
//    if(r<=mid)return ask(2*x,tl,mid,l,r);
//    else if(l>mid)return ask(2*x+1,mid+1,tr,l,r);
//    else{
//        return ask(2*x,tl,mid,l,mid)+ask(2*x+1,mid+1,tr,mid+1,r);
//    }
//}
//void build(int x,int l,int r)
//{
//    if(l==r)
//    {
//        t[x].sum=a[l];
//        return ;
//    }
//    int mid = (l+r)>>1;
//    build(2*x,l,mid);
//    build(2*x+1,mid+1,r);
//    t[x].sum = t[2*x].sum+t[2*x+1].sum;
//}
//int main()
//{
//
//    return 0;
//}
#include <bits/stdc++.h>

using namespace std;
#define maxn 100007  //元素总个数
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
int Sum[maxn<<2],Add[maxn<<2];//Sum求和,Add为懒惰标记
int A[maxn],n;//存原数组数据下标[1,n]
//PushUp函数更新节点信息 ,这里是求和
void PushUp(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}
//Build函数建树
void Build(int l,int r,int rt){ //l,r表示当前节点区间,rt表示当前节点编号
	if(l==r) {//若到达叶节点
		Sum[rt]=A[l];//储存数组值
		return;
	}
	int m=(l+r)>>1;
	//左右递归
	Build(l,m,rt<<1);
	Build(m+1,r,rt<<1|1);
	//更新信息
	PushUp(rt);
}

void PushDown(int rt,int ln,int rn){
	//ln,rn为左子树,右子树的数字数量。
	if(Add[rt]){
        cout << rt <<endl;
		//下推标记
		Add[rt<<1]+=Add[rt];
		Add[rt<<1|1]+=Add[rt];
		//修改子节点的Sum使之与对应的Add相对应
		Sum[rt<<1]+=Add[rt]*ln;
		Sum[rt<<1|1]+=Add[rt]*rn;
		//清除本节点标记
		Add[rt]=0;
	}
}
void Update(int L,int C,int l,int r,int rt){//l,r表示当前节点区间,rt表示当前节点编号
	if(l==r){//到叶节点,修改
		Sum[rt]+=C;
		return;
	}
	int m=(l+r)>>1;
	//根据条件判断往左子树调用还是往右
	if(L <= m) Update(L,C,l,m,rt<<1);
	else       Update(L,C,m+1,r,rt<<1|1);
	PushUp(rt);//子节点更新了,所以本节点也需要更新信息
}
void Update(int L,int R,int C,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
    cout << l <<' '<<r <<endl;
	if(L <= l && r <= R){//如果本区间完全在操作区间[L,R]以内
		Sum[rt]+=C*(r-l+1);//更新数字和,向上保持正确
		Add[rt]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
		return ;
	}
	int m=(l+r)>>1;

	PushDown(rt,m-l+1,r-m);//下推标记
	//这里判断左右子树跟[L,R]有无交集,有交集才递归
	if(L <= m) Update(L,R,C,l,m,rt<<1);
	if(R >  m) Update(L,R,C,m+1,r,rt<<1|1);
	PushUp(rt);//更新本节点信息
}
int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号

	if(L <= l && r <= R){
		//在区间内,直接返回
		return Sum[rt];
	}
	int m=(l+r)>>1;
	//下推标记,否则Sum可能不正确
	PushDown(rt,m-l+1,r-m);

	//累计答案
	int ANS=0;
	if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
	if(R >  m) ANS+=Query(L,R,m+1,r,rt<<1|1);
	return ANS;
}
int main()
{
    cin >> n;
    for(int i =1;i <=n;i++)
        cin >> A[i];
	//建树
	Build(1,n,1);
	int ANS=Query(1,n,1,n,1);
	cout << ANS <<endl;
	//点修改
//	Update(L,C,1,n,1);
	//区间修改
	Update(1,5,1,1,n,1);
	//区间查询
	ANS=Query(1,n,1,n,1);
	cout << ANS<<endl;
    return 0;
}

字符串哈希

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5+5;
const int X=131;
ull pre[maxn],suf[maxn],p[maxn];
char s[maxn];
int n;
void Hash()
{
    p[0]=1;
    for(int i =1;i<=n;i++)
    {
        pre[i]=pre[i-1]*X+s[i]-'a'+1;
        p[i]=p[i-1]*X;
    }
    for(int i = n;i>=1;i--)
    {
        suf[i]=suf[i+1]*X+s[i]-'a'+1;
    }
}
ull getpre(int l,int r)
{
    return pre[r]-pre[l-1]*p[r-l+1];
}
ull getsuf(int l,int r)
{
    return suf[l]-suf[r+1]*p[r-l+1];
}
bool eql(int l1,int r1,int l2,int r2)
{
    return getpre(l1,r1)==getpre(l2,r2);
}
bool huiwen(int r)
{
    return getpre(1,r/2)==getsuf(ceil(r*1.0/2)+1,r);
}
bool check(int r)
{
    if(r&1)
    {
        return huiwen((r+1)/2)&&eql(1,(r+1)/2,(r+1)/2,r);
    }
        return huiwen(r/2)&&eql(1,r/2,r/2+1,r);
}
int main()
{
    cin >> s+1;
    n=strlen(s+1);
    Hash();
    int ans=0;
    for(int i = 1;i <= n;i++)
    {
        if(check(i))ans++;
    }
    printf("%d\n",ans);
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值