noip模板不完全名录
目录
- 图论部分
- spfa
- dijkstra
- floyd
- LCA
- 树上差分
- 最小生成树
- 拓扑排序
- 数学部分
- 逆元,费马小定理(附快速幂)
- 不定方程求解,exgcd
- 线性素数筛
图论
1.spfa
queue <int> q;
int d[100003];
bool v[100003];
void spfa(int s)
{
q.push(s);
for(int i=1;i<=n;i++)
d[i]=MAX;
d[s]=0;
while(!q.empty())
{
int tmp=q.front();
q.pop();
v[tmp]=0;
for(int i=h[tmp];i;i=e[i].nxt)
if(d[tmp]+e[i].capa<d[e[i].too])
{
d[e[i].too]=d[tmp]+e[i].capa;
if(!v[e[i].too])//注意要判定是否在队列内,不然就是Bellman-ford了
{
v[e[i].too]=1;
q.push(e[i].too);
}
}
}
}
2.dijkstra(堆优化)
struct node
{
int u;
long long v;//特别注意long long
};
bool operator < (node a,node b)
{
return a.v>b.v;
}//重载小于号,为了将大根堆改为小根堆,小根堆反了!
priority_queue<node> heap;//优先和堆之间有一个下划线
void dijkstra()
{
for(int i=1;i<=n;i++)
dist[i]=inf;
dist[s]=0;
heap.push((node) {s,0});
node tmp;
while(heap.empty()==0)
{
tmp=heap.top();
heap.pop();
if(tmp.dis>d[tmp.p]) continue;//只用在距离上有就可以
for(int i=h[tmp.u];i;i=e[i].nxt)//往周围广搜
if(dist[e[i].too]>dist[e[i].from]+e[i].capa)
{
dist[e[i].too]=dist[e[i].from]+e[i].capa;
heap.push((node){e[i].too,dist[e[i].too]});//将改变距离的加入优先队列
}
}
}
3.floyd(现在有更先进的Johnson全源最短路了)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=0x3fffffff;
for(int i=1;i<=n;i++)
d[i][i]=0;//不要忘记预处理!!
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(d[j][k]<d[j][i]+d[i][k])//变量位置好像只要保证前后对应就可以了,内外层没有影响
d[j][k]=d[j][i]+d[i][k];
4.LCA
int fa[500005][22],dep[500005];
void dfs(int ff,int ss,int d)//处理fa数组的初始值和深度
{
fa[ss][0]=ff;
dep[ss]=d;
for(int i=h[ss];i;i=e[i].nxt)
if(e[i].too!=ff)
dfs(ss,e[i].too,d+1);
}
void bz()//建立倍增,外层幂数内层点
{
for(int i=1;i<=19;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int xx,int yy)//深度定位置,倍增同深度,一同向上找祖先
{
if(xx==yy) return xx;
if(dep[xx]<dep[yy]) swap(xx,yy);//深度定位置
for(int i=19;i>=0;i--)
if(dep[xx]-dep[yy]>=(1<<i))
xx=fa[xx][i];////倍增同深度
if(xx==yy) return xx;
for(int i=19;i>=0;i--)
if(fa[xx][i]!=fa[yy][i])
{
xx=fa[xx][i];
yy=fa[yy][i];
}//一同向上找祖先
return fa[xx][0];
}
5.树上差分
int sign[300005]
void put_sign()
{
for(int i=1;i<=PATHNUM;i++)
{
sign[path_begin[i]]++;
sign[path_end[i]]++;
sign[lca(path_begin[i],path_end[i])]-=2;
}
}
int updata(int p)//每个点上储存的是该点到父亲节点上的连线被经过多少次
{
if(h[p]==0) return sign[p];
for(int i=h[p];i;i=e[i].nxt)
sign[p]+=updata();
return sign[p];
}
6.最小生成树(kruscal)
void build()
{
for(int i=1;i<=n;i++)
f[i]=i;
sort(e+1,e+1+m,cmp);
int cnt=0;bool flag=0;
for(int i=1;i<=m;i++)
{
if(find(e[i].from)!=find(e[i].too))
{
cnt++;//考虑要不要再建图存下这条边
merge(e[i].from,e[i].too);
}
if(cnt==n-1)
{
flag=1;
return;
}
}
}
7.拓扑排序
int a[10003];
queue <int> q;
void toposort()
{
for(int i=1;i<=n;i++)
if(!in[i])
q.push(i),a[++a[0]]=i;
while(!q.empty())
{
int tmp=q.front();
q.pop();
for(int i=h[tmp];i;i=e[i].nxt)
{
in[e[i].too]--;
if(!in[e[i].too])
q.push(e[i].too),a[++a[0]]=e[i].too;
}
}
}
数学
1.逆元 费马逆元
long long ksm(long long aa,long long bb)
{
long long r=aa;long long ans=1;
while(bb)
{
if((bb&1)==1)
ans=(ans*r)%p;
r=(r*r)%p;
bb/=2;
}
}
long long fmny()//费马逆元
{
return ksm(x,p-2);
}
2.exgcd
int x,y;
int exgcd(int a,int b)
{
if(b==0)
{
x=1;y=0;
return a;
}
int g=exgcd(b,a%b);
int tmp=x;
x=y;
y=tmp-a/b*y;
return g;
}
int minn(int a,int b,int x,int y)
{
int g=exgcd(a,b);
if(x<0)
while(x<0)
x=x+b*g
else
while(x>0)
x=x-b*g
x=x+b*g;
}
附一段推导(由于本人太菜有些地方不会推,这里只有部分推导)
当\(b=0\)时,\(ax+by=gcd(a,0)=a\) 则此时x=1,(y什么值都可以赋过去)
当\(b!=0\)时,(此处\(a/b\)均为向下取整的意思)
\(ax+by=gcd(a,b)\)
\(=gcd(b,a\%b)\)
\(=bx_1+(a\%b)y_1\)
\(=bx_1+(a-(a/b)*b)y_1\)
\(=ay_1+b[ x_1+(a/b)y_1 ]\)
即\(x=y_1\),\(y=x_1+(a/b)y_1\)为公式中的递归式
而int g=gcd(b,a%b)就是\(ax+by=bx_1+(a\%b)y1\)中变过来的
3.线性素数筛
bool is_not_prime[10000003];
int prime[10000003]
void p()
{
is_not_prime[1]=1;
for(int i=2;i<=n;i++)
{
if(!is_not_prime[i])
prime[++num]=i;
for(int j=1;j<=num&&i*prime[j]<=n;j++)
{
is_not_prime[i*prime[j]]=1;
if(!i%prime[j])
break;//筛到前一个能mod后为0
}
}
}
But a man is not made for defeat.A man can be destroyed but not defeated.

浙公网安备 33010602011771号