大部分模板为代码片段,可能有少部分的完整程序
邻接表
struct os
{
int fa,son,next,v;
}a[100000];//边数
int first[10000]//点数
//定义
void add(int x,int y,int z)
{
a[++tot].fa=x;
a[tot].son=y;
a[tot].v=z;
a[tot].next=first[x];
first[x]=tot;
}
……
for (int i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),
add(x,y,z),
//add(y,x,z);有向图时不用这条
//建边
for (int i=first[x];i;i=a[i].next)
……
//调用所有以x为出点的边
矩阵乘法(mod为取模数)
struct matrix
{
int map[130][130];
};
matrix mul(matrix a,matrix b)
{
matrix c;
memset(c.map,0,sizeof(c.map));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
c.map[i][j]=(c.map[i][j]+(a.map[i][k]*b.map[k][j]%mod))%mod;
return c;
}
矩阵快速幂(配合上面使用)
matrix qr(matrix a,int b)
{
matrix c;
c=a;
b--;
while (b)
{
if (b&1) c=mul(c,a);
a=mul(a,a);
b>>=1;
}
return c;
}
普通快速幂
int qr(int x,int y,int z)
{
int ans=1;
x%=z;
while (y)
{
if (y&1) ans=ans*x%z;
x=x*x%z;
y>>=1;
}
return ans;
}
欧拉筛(求1-n的phi和质数)
int prime[1000000],phi[1000000]
……
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!pd[i])
prime[++prime[0]]=i,phi[i]=i-1;
for (int j=1;j<=prime[0];j++)
{
if (prime[j]*i>n) break;
pd[prime[j]*i]=1;
if (i%prime[j]==0) {phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
求逆元
void exgcd(int a,int b,int &x,int &y)
{
if (b==0) {x=1;y=0;return;}
exgcd(b,a%b,x,y);
int x1=y,y1=x-a/b*y;
x=x1;y=y1;
}
int getinv(int p)
{
int x,y;
exgcd(p,r,x,y);
return (x%r+r)%r;
}
位运算小技巧:http://blog.csdn.net/xym_csdn/article/details/50725540
Lucas定理
……
#define LL long long
……
LL lucas(LL p,LL q,LL num)
{
LL sum=1;
while (p&&q)
{
LL x=p%prime[num],y=q%prime[num];
if (y>x) return 0;
sum=(sum*(fac[x]*qr(fac[y]*fac[x-y],prime[num]-2,prime[num]))%prime[num])%prime[num];
p/=prime[num];
q/=prime[num];
}
return sum;
}
……
for (LL j=1;j<=prime[i];j++)
fac[j]=fac[j-1]*j%mod;
SPFA(邻接表)
#include<bits/stdc++.h>
using namespace std;
struct os
{
int fa,son,next,w;
}a[100010];
bool flag[10010];
int first[10010],tot,dis[10010],n,m,x,y,z;
queue <int>q;
void add(int x,int y,int z)
{
a[++tot].fa=x;
a[tot].son=y;
a[tot].w=z;
a[tot].next=first[x];
first[x]=tot;
}
main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),
add(x,y,z);
// add(y,x,z);//是无向图就去掉注释
memset(dis,63,sizeof(dis));
dis[1]=0;
q.push(1);
flag[1]=1;
while (!q.empty())
{
int t=q.front();
flag[t]=0;
q.pop();
for (int i=first[t];i;i=a[i].next)
{
int p=a[i].son;
if (dis[t]+a[i].w<dis[p])
{
dis[p]=dis[t]+a[i].w;
if (!flag[p]) q.push(p),flag[p]=1;
}
}
}
printf("%d",dis[n]);
}
快速读入
int in()
{
int f=1,t=0;
char ch=getchar();
while (ch>'9'||ch<'0')
{
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
return f*t;
}
秦九韶算法
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,x,a[100000];
LL ans;
main()
{
scanf("%d%d",&n,&x);
for(int i=0;i<=n;i++) scanf("%d",&a[i]);
for (int i=n;i>=0;i--)
ans=ans*x+a[i];
printf("%lld",ans);
}
单调队列
给定一个长度为N的整数数列a(i),i=0,1,…,N-1和窗长度k.
要求:
f(i)=max(a(i−k+1),a(i−k+2),...,a(i))i=1,2,3,..n
#include<bits/stdc++.h>
using namespace std;
int x,n,k,head=1,tail;
struct os
{
int data,num;
}q[500000];
main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
if (head<=tail&&i-q[head].num>=k) head++;
while (head<=tail)
{
if (q[tail].data>x) break;
tail--;
}
q[++tail].data=x;
q[tail].num=i;
if (i>=k) printf("%d ",q[head].data);
}
}
邻接表+堆优化dijskra求最短路
点对中的优先级比较first>second,所以把dis当成first
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int tot,n,m;
int first[10010],dis[10010];
bool flag[10010];
struct os
{
int w,u,v,next;
}e[200010];
void add(int x,int y,int z)
{
e[++tot].u=x;
e[tot].v=y;
e[tot].w=z;
e[tot].next=first[x];
first[x]=tot;
}
typedef pair<int,int> xy;
priority_queue<xy,vector<xy>,greater<xy> >q;
main()
{
scanf("%d%d",&n,&m);
int x,y,z;
for (int i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),
add(x,y,z),add(y,x,z);//无向图
memset(dis,63,sizeof(dis));
dis[1]=0;
q.push(make_pair(dis[1],1));
while (!q.empty())
{
xy now=q.top();
q.pop();
if (flag[now.second]) continue;
flag[now.second]=1;
for (int i=first[now.second];i;i=e[i].next)
if (dis[now.second]+e[i].w<dis[e[i].v])
{
dis[e[i].v]=dis[now.second]+e[i].w;
if (!flag[e[i].v]) q.push(make_pair(dis[e[i].v],e[i].v));
}
}
printf("%d",dis[n]);
}
kmp算法(求ch在s中第一次出现的位置)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
char s[100002],ch[102];
int l,next[102];
main()
{
scanf("%s%s",s,ch);
for (int i=1;i<strlen(ch);i++)
{
int k=i;
while (ch[i]!=ch[next[k]]&&next[k]) k=next[k];
next[i+1]=next[k]+(ch[i]==ch[next[k]]);
}
int now=0;
for (int i=0;i<strlen(s);i++)
{
while (ch[now]!=s[i]&&now) now=next[now];
now+=(ch[now]==s[i]);
if (now==strlen(ch)) {printf("%d\n",i-now+1);break;}
}
}
AC自动机:AC自动机练习
LCT:弹飞绵羊
莫队:小Z的袜子
Splay(这个特别丑,可以看别的题解):普通平衡树
背包:背包小例题
欧拉筛求φ,μ,d
#include<cstdio>
using namespace std;
int n,prime[1000010];
bool flag[1000010];
int t[1000010],d[1000010],mu[1000010],phi[1000010];
main()
{
scanf("%d",&n);
mu[1]=1;d[1]=1;
for (int i=2;i<=n;i++)
{
if (!flag[i])
prime[++prime[0]]=i,
mu[i]=-1,
phi[i]=i-1,
t[i]=i,
d[i]=2;
for (int j=1;j<=prime[0];j++)
{
if (i*prime[j]>n) break;
flag[prime[j]*i]=1;
if (i%prime[j])
{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
mu[i*prime[j]]=-mu[i];
t[i*prime[j]]=1;
d[i*prime[j]]=d[i]<<1;
}
else
{
phi[i*prime[j]]=phi[i]*prime[j];
mu[i*prime[j]]=0;
t[i*prime[j]]=t[i]+1;
d[i*prime[j]]=d[i]/(t[i]+1)*(t[i]+2);
break;
}
}
}
}
O(n)求1-n的逆元(mod为质数)
证明
#include<cstdio>
using namespace std;
int n,mod,inv[100000];
main()
{
scanf("%d%d",&n,&mod);
inv[1]=1;
printf("1 ");
for (int i=2;i<=n;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod,
printf("%d ",inv[i]);
}
匈牙利
bool find(int x)
{
for (int i=first[x];i;i=e[i].next
if (!vis[e[i].v])
{
vis[e[i].v]=1;
if (!belong[e[i].v]||find(belong[e[i].v]))
{
belong[e[i].v]=x;
return 1;
}
}
return 0;
}
tarjan
定义:
int low[],dfn[],cnt,first[];
bool vis[];
stack<int>s
struct edge{int v,next;}
操作:
void dfs(int x)
{
low[x]=dfn[x]=++cnt;
vis[x]=1;s.push(x);
for (int i=first[x];i;i=e[i].next)
if (!dfn[e[i].v])
dfs(e[i].v),
low[x]=min(low[x],low[e[i].v]);
else if (vis[e[i].v])
low[x]=min(low[x],dfn[e[i].v];
if (dfn[x]==low[x])
for (int y=-1;y!=x;y=s.top(),s.pop())
vis[s.top()]=1,
//...
}