模板总复习

啊还有十天不到就要noip提高组了,还是觉得好慌张,周围一大堆大佬,唔菜鸡还是背背模板吧。

每天一个部分好啦。

第一部分:数论+线段树+树状数组+rmq+最短路+最小生成树(是不是觉得非常的繁杂哈哈哈我就喜欢先上一大堆最主要的)

快速幂

用途:用来计算a^b mod n的值,且复杂度为log级

假设我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时a^11=a^(2^0+2^1+2^3)

11的二进制是1011,11 = 23×1 + 22×0 + 21×1 + 2o×1,因此,我们将a11转化为算 a^(2^0)*a^(2^1)*a^(2^3) ,由于是二进制,很自然地想到用位运算这个强大的工具:

&  和 >>

&运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。还可以判断奇偶x&1==0为偶,x&1==1为奇。     >>运算比较单纯,二进制去掉最后一位。

function pow(a,b:longint):longint;
var ans,base:longint;
begin
  ans:=1; base:=a;
  while b<>0 do
    begin
      if b and 1<>0 then ans:=ans*base;
      base:=base*base;
      b:=b>>1;
    end;
  exit(ans);
end;

矩阵乘法

//p是第一个矩阵的行数
//q是第二个矩阵的行数
//r是第二个矩阵的列数
  for i:=1 to p do
    for j:=1 to r do
        for k:=1 to q do
          c[i,j]:=c[i,j]+a[i,k]*b[k,j];

扩展欧几里得

若存在一组解x0,y0,满足b*x0+(a mod b)*y0=d则取x=y0,y=x0-(a div b)*y0,有ax+by=d这样,我们可以用类似辗转相除的迭代法求解。

function exgcd(a,b:longint;var x,y:longint):longint;
var d,tmp:longint;
begin
   if b=0 then
     begin
       x:=1; y:=0;
       exit(a);
     end
   d:=exgcd(b,a mod b,x,y);
   tmp:=x; x:=y; y:=tmp-a div b*y;
   exit(d);
end;

逆元

什么叫乘法逆元?

这里,我们称 x 是 a 关于 m 的乘法逆元

这怎么求?可以等价于这样的表达式: a*x + m*y = 1

欧拉函数

欧拉函数用希腊字母φ表示,φ(N)表示N的欧拉函数.

对φ(N)的值,我们可以通俗地理解为小于N且与N互质的数的个数(包含1).

1.对于素数p, φ(p)=p-1,对于对两个素数p,q φ(pq)=pq-1

欧拉函数是积性函数,但不是完全积性函数.

即φ(mn)=φ(n)*φ(m)只在(n,m)=1时成立.

2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn.

φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn).

3.除了N=2,φ(N)都是偶数.

4.设N为正整数,∑φ(d)=N (d|N).

根据性质2,我们可以在O(sqrt(n))的时间内求出一个数的欧拉函数值.

如果我们要求1000000以内所有数的欧拉函数,怎么办.

上面的方法复杂度将高达O(N*sqrt(N)).

//求一个n的小于等于n的互质的数的个数
function euler(n:longint):longint;
var res,a,i:longint;
begin
  res:=n; a:=n;
  for i:=2 to trunc(sqrt(a)) do
    if a mod i=0 then
      begin
        res:=(res div i)*(i-1);
        while a mod i=0 do a:=a div i;
      end;
  if a>1 then res:=(res div a)*(a-1);
  exit(res);
end;
//筛法求所有的欧拉函数
procedure init;
var  i,j:longint;
begin
  fillchar(p,sizeof(p),0);
  p[1]:=1;
  for i:=2 to 100000 do
    if p[i]=0 then
      begin
        j:=i;
          while (j<=100000) do
            begin
              if p[j]=0 then p[j]:=j;
              p[j]:=p[j] div i*(i-1);
              j:=j+i;
            end;
      end;
end;

线段树

//区间求和
var  t,x,y,n,k,tap:int64;
i:longint;
a:array[0..1000005]of int64;
tree,mark:array[0..4000005]of int64;
procedure build(root,t,w:longint);
var mid:longint;
begin
 {}mark[root]:=0;
 if t=w then tree[root]:=a[t]
  else
   begin
     mid:=(t+w) div 2;
     build(root*2,t,mid);
     build(root*2+1,mid+1,w);
     tree[root]:=tree[root*2]+tree[root*2+1];
   end;
end;
procedure pushdown(root,mid,tt,ww:longint);
begin
  if mark[root]<>0 then
    begin
      inc(mark[root*2],mark[root]);
      inc(mark[root*2+1],mark[root]);

      inc(tree[root*2],mark[root]*(mid-tt+1));
      inc(tree[root*2+1],mark[root]*(ww-mid));
      mark[root]:=0;
    end;
end;
function find(root,tt,ww,t,w:longint):int64;
var mid:longint;
begin
  if (t>ww)or(w<tt) then exit(0);
  if (t<=tt)and(w>=ww) then exit(tree[root]);
  mid:=(tt+ww) div 2;
  {}pushdown(root,mid,tt,ww);
  exit(find(root*2,tt,mid,t,w)+find(root*2+1,mid+1,ww,t,w));
end;
procedure update(root,tt,ww,t,w,x:longint);
var mid:longint;
begin
  if (tt>w)or(ww<t)then exit;
  if (t<=tt)and(ww<=w) then
    begin
      inc(mark[root],x);
      inc(tree[root],x*(ww-tt+1));
      exit;
    end;
  mid:=(tt+ww) div 2;
  pushdown(root,mid,tt,ww);
  update(root*2,tt,mid,t,w,x);
  update(root*2+1,mid+1,ww,t,w,x);
  tree[root]:=tree[root<<1]+tree[1+(root<<1)];
end;
begin
 readln(n,k);
 for i:=1 to n do read(a[i]);
 build(1,1,n);
 for i:=1 to k do
  begin
    read(t,x,y);
    if t=1 then
        begin
         read(tap);
         update(1,1,n,x,y,tap);
        end
         else
          writeln(find(1,1,n,x,y));
  end;
end.

树状数组

//树状数组程序
function lowbit(x:longint):longint;
begin exit(x and(-x));end;
procedure add(x,y:longint);
var i:longint;
begin
  i:=x;
  while i<=n do
   begin
    tree[i]:=tree[i]+y;
    i:=i+lowbit(i);
   end;
end;
function sum(x:longint):longint;
var i,ans:longint;
begin
 ans:=0; i:=x;
 while i>0 do
  begin
    ans:=ans+tree[i];
    i:=i-lowbit(i);
  end;
 exit(ans);
end;
//标准
begin
  readln(n,m);
  for i:=1 to n do
    begin  read(a[i]);  add(i,a[i]); end;
  for i:=1 to m do
   begin
     read(c);
     if c=1 then
       begin readln(x,k); add(x,k);end
         else begin read(x,y); writeln(sum(y)-sum(x-1));end;
   end;
end.
//差分求和
begin
 readln(n,m);
 y:=0;
 for i:=1 to n do
   begin
     read(x); add(i,x-y); y:=x;
   end;
 for i:=1 to m do
  begin
    read(f);
    if f=1 then
      begin
        read(x,y,z);
        add(x,z); add(y+1,-z);
      end
        else
         begin   read(x);  writeln(sum(x)); end;
  end;
end.

RMQ

var  n,i,j,m,a,b:longint;
f:array[0..100000,0..21]of longint;
function min(a,b:longint):longint;
begin if a<b then exit(a) else exit(b); end;
begin
  readln(n,m);
  for i:=1 to n do read(f[i,0]);
  for j:=1 to trunc(ln(n)/ln(2)) do
    for i:=1 to n do
      if (i+1<<(j-1)<=n) then
      f[i,j]:=min(f[i,j-1],f[i+(1<<(j-1)),j-1]);
  // F[i,j]表示从i开始到i+2的j次 -1这个区间中的最大值
  for i:=1 to m do
    begin
      read(a,b);
      j:=trunc(ln(b-a+1)/ln(2));
      write(min(f[a,j],f[b-(1<<j)+1,j]),‘ ‘);
    end;
end.

最短路-dijkstra

//单源最短路径(无堆优化)
procedure Dijkstra(s:longint);
var v,i,u,j:longint;
min:int64;
begin
  fillchar(vis,sizeof(vis),false);
  dis[s]:=0;
  for i:=1 to n do
    begin
      min:=2147483647;
      for j:=1 to n do
        if (vis[j]=false)and(dis[j]<min)then
          begin
            min:=dis[j];
            u:=j;
          end;
      vis[u]:=true;
      for v:=1 to n do
        if (vis[v]=false)and(dis[u]+f[u,v]<dis[v]) then
           dis[v]:=dis[u]+f[u,v];
    end;
  for i:=1 to n do write(dis[i],‘ ‘);
end;
begin
  readln(n,m,s);
  for i:=1 to n do
    for j:=1 to n do f[i,j]:=2147483647;
  for i:=1 to n do  dis[i]:=2147483647;
  for i:=1 to m do
    begin
      read(a,b,c);
      f[a,b]:=min(c,f[a,b]);
    end;
  Dijkstra(s);
end.
{single source shortest path}+堆优化
{假设一个图的最大节点数为1000,所有运算在integer范围内}
{程序目标:给定有向图的邻接表,求出节点1到节点n的最短路径长度}
const maxn=1000;{最大节点数}
var
 n:integer;{节点个数}
 deg:array[1..maxn] of integer;{每个节点的度数}
 list:array[1..maxn,1..maxn,1..2] of integer;{邻接表,第一个元素表示边的中点,第二个元素表示边的长度}
 count:integer;{堆内元素个数计数器}
 heap:array[1..maxn] of integer;{heap[i]表示堆内的第i的元素的节点编号}
 pos:array[1..maxn] of integer;{表示编号为i的元素在堆内的位置}
 key:array[1..maxn] of integer;{表示节点1到节点i的最短距离}
 exist:array[1..maxn] of boolean;{表示节点i是否存在于堆中}
 i,j,now:integer;

swap别忘了var!!!!!!

procedure heapify(p:integer);{调整堆的过程}
var best:integer;
begin
  best:=p;
  if (p*2<=count) and (key[heap[p*2]]<key[heap[best]]) then best:=p*2;
  if (p*2+1<=count) and (key[heap[p*2+1]]<key[heap[best]]) then best:=p*2+1;
  if best<>p then
    begin
      swap(pos[heap[p]],pos[heap[best]]);
      swap(heap[p],heap[best]);
      heapify(best);
    end;
end;

procedure modify(id,new_key:integer);{判断new_key与key[id]大小,并修改key[id]大小}
var p:integer;
begin
  if (new_key<key[id]) then
    begin
      key[id]:=new_key;
      p:=pos[id];
      while (p>1) and (key[heap[p]]<key[heap[p div 2]]) do
        begin
          swap(pos[heap[p]],pos[heap[p div 2]]);
          swap(heap[p],heap[p div 2]);
          p:=p div 2;
        end;
    end;
end;

procedure extract(var id,dis:integer);{读取堆中最小元素的节点编号和节点1到该节点的距离}
begin
  id:=heap[1];
  dis:=key[id];
  dec(count);
  if (count>0) then
    begin
      swap(pos[heap[1]],pos[heap[count+1]]);
      swap(heap[1],heap[count+1]);
      heapify(1);
    end;
end;

begin
readln(n);
for i:=1 to n do
  begin
    read(deg[i]);
    for j:=1 to deg[i] do read(list[i,j,1],list[i,j,2]);
  end;
for i:=1 to n do
  begin
    exist[i]:=true;
    pos[i]:=i;
    heap[i]:=i;
    key[i]:=maxint;
  end;
count:=n;
key[1]:=0;
{dijkstra算法}
while (count>0) do
  begin
    extract(i,now);
    if now=maxint then break;
    for j:=1 to deg[i] do
    if exist[list[i,j,1]] then modify(list[i,j,1],now+list[i,j,2]);
  end;
if key[n]=maxint then writeln(‘Not Connected!‘){节点1和节点n不连通}
else writeln(key[n]);{连通}
end.

最短路-Floyd(多源求最短路)不上代码了

最短路-SPFA

var tot,x,y,z,i,n,m:longint;
head,next,key,value:array[0..40000]of longint;
dis,q:array[0..100000]of longint;
vis:array[0..100000]of boolean;
procedure add(x,y,z:longint);
begin
  tot:=tot+1;
  next[tot]:=head[x];
  head[x]:=tot;
  key[tot]:=y;
  value[tot]:=z;
end;
procedure spfa(s:longint);
var i,h,t,u,v:longint;
begin
  fillchar(vis,sizeof(vis),false);
  for i:=1 to n do   dis[i]:=10000000;
  dis[s]:=0;q[1]:=s;
  h:=0; t:=1;
  vis[s]:=true;
  while(h<t) do
    begin
      h:=h+1;  u:=q[h]; i:=head[u];
      vis[u]:=false;
      while(i<>0) do
        begin
          v:=key[i];
          if (dis[v]>dis[u]+value[i]) then
            begin
              dis[v]:=dis[u]+value[i];
              if (vis[v]=false) then
                begin
                t:=t+1;
                q[t]:=v;
                vis[v]:=true;
                end;
            end;
          i:=next[i];
        end;
    end;
end;
begin
  readln(n,m);
  while (n<>0) do
   begin
     tot:=0;
     fillchar(head,sizeof(head),0);
     for i:=1 to m do
       begin
         read(x,y,z);
         add(x,y,z);
         add(y,x,z);
       end;
    spfa(1);
    writeln(dis[n]);
    readln(n,m);
   end;
end.

并查集(带权)

//带权并查集
function find(x:longint):longint;
var tmp:longint;
begin
    if father[x]=x then exit(x);
    tmp:=father[x];
    father[x]:=find(father[x]);
    //下面一句可以随意改
    value[x]:=value[tmp]+1;
    exit(father[x]);
end;
//食物链
var
n,m,i,ans:longint;
father,size:array[0..50000]of longint;
function find(x:longint):longint;
var t:longint;
begin
    if father[x]=x then exit(x)
        else
            begin
                t:=father[x];
                father[x]:=find(father[x]);            //路径压缩
                size[x]:=(size[x]+size[t]) mod 3;
                //根据找规律可得,各种情况两两结合可得size
                exit(father[x]);
            end;
end;
function judge:boolean;
var kind,x,y,fx,fy:longint;
begin
    //以下的各种判定可用向量的规律判断得
    readln(kind,x,y);
    if (x>n)or(y>n) then exit(false);
    if (kind=2)and(x=y) then exit(false);
    fx:=find(x);     fy:=find(y);
    if fx=fy then
        begin
            if (size[y]-size[x]+3) mod 3<>(kind-1) then exit(false)
                else exit(true);
        end
    else
        begin
            father[fy]:=fx;
            size[fy]:=(size[x]-size[y]+kind-1+3) mod 3;
            exit(true);
        end;
end;
begin
    readln(n,m);
    for i:=1 to n do
        begin
            father[i]:=i;
            size[i]:=0;
        end;
    for i:=1 to m do
        if judge=false then ans:=ans+1;
    writeln(ans);
end.

最小生成树-Prim

算法思想:普里姆算法构造最小生成树的过程是从一个顶点U={u0}作初态,不断贪心寻找与U中顶点相邻且代价最小的边的另一个顶点,扩充到U集合直至U=V为止。

const
  max=1000;
var
  map:array[1..MXN,1..MXN] of longint;
  cost:array[1..MXN] of longint;
  visit:array[1..MXN] of boolean;
  i,j,n,m,x,y,v:longint;
function prim():longint;
  var
   i,j,min,mini,ans:longint;
  begin
   ans:=0;
   for i:=1 to n do begin visit[i]:=false;cost[i]:=maxlongint;end;
//visit[i]是i点是否被访问的标志,cost[i]是到i点的最小权边。
   for i:=2 to n do
     if map[1,i]<>0 then cost[i]:=map[1,i];visit[1]:=true;
for i:=1 to n-1 do
    begin
     min:=maxlongint;
     for j:=1 to n do
        if not visit[j] and (cost[j]<min) then
           begin min:=cost[j];mini:=j;end;
     visit[mini]:=true;inc(ans,min);
     for j:=1 to n do
      if not visit[j] and (map[mini,j]>0) and (map[mini,j]<cost[j]) then cost[j]:=map[mini,j];
//更新圈内圈外存储的最短距离
    end;
   exit(ans);
  end;
begin
  readln(n,m);
  for i:=1 to m do
   begin
    readln(x,y,v);
    if (map[x,y]=0) or (map[x,y]>v) then
     begin
      map[x,y]:=v;map[y,x]:=v;
     end;
   end;
  writeln(prim());
end.

最小生成树-Kruskal算法

先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。
  时间复杂度为为O(e^2), 使用并查集优化后复杂度为 O(eloge),与网中的边数有关,适用于求边稀疏的网的最小生成树。

设图G的度为,G=(V,E),设该图的最小生成树为T=(V,TE),设置边的集合TE的初始状态为空集。将图G中的边按权值从小到大排好序,然后从小的依次开始选取,若选取得边使生成树T不形成回路,则把它并入TE中,保留作为T的一条边;若选取得边使生成树形成回路,则舍弃;如此继续进行,直到使TE中包含n-1条边为止。

const MXN=1000;
 type
  rqmap=record
   s,t,v:longint;
  end;
 var
  map:array[1..MXN*MXN] of rqmap;
  father:array[1..MXN] of longint;
  n,m,i,ingraph,ans:longint;
procedure qsort(b,e:longint);//排序
  var
   i,j,x:longint;
   t:rqmap;
  begin
   i:=b;j:=e;x:=map[(i+j)>>1].v;
   while (i<=j) do
    begin
     while (map[i].v<x) do inc(i);
     while (map[j].v>x) do dec(j);
     if (i<=j) then begin t:=map[i];map[i]:=map[j];map[j]:=t;inc(i);dec(j);end;
    end;
   if i<e then qsort(i,e);
   if j>b then qsort(b,j);
  end;
 function find(x:longint):longint;
  begin
   if (father[x]=x) then exit(x);
   father[x]:=find(father[x]);//路径压缩
   exit(father[x]);
  end;
procedure union(a,b:longint); //并查集
  begin
   father[find(a)]:=find(father[b]);
  end;
 begin
readln(n,m);
  for i:=1 to n do father[i]:=i;
  for i:=1 to m do readln(map[i].s,map[i].t,map[i].v);
  qsort(1,m);ans:=0;ingraph:=1;i:=0;
  while (ingraph<n) do
   begin
    inc(i);
    if find(map[i].s)<>find(map[i].t) then
     begin
      inc(ingraph);inc(ans,map[i].v);union(map[i].s,map[i].t);
     end;
   end;
  writeln(ans);
end.

拓扑排序

将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。

var
  map:array[0..101,0..101]of longint;
    c,d:array[0..101]of longint;
    flag:array[0..101]of boolean;
    i,j,k,n,x,y:longint;
    check:boolean;
begin
  fillchar(map,sizeof(map),false);
    fillchar(c,sizeof(c),0);
    fillchar(d,sizeof(d),0);
    readln(n);
    while not eof do begin
      readln(x,y);
        inc(c[x]);
        inc(d[y]);
        map[x,c[x]]:=y;
    end;
  fillchar(flag,sizeof(flag),false);
    for k:=1 to n do begin
      for i:=1 to n do
      if (flag[i]=false)and(d[i]=0) then begin
            write(i,‘ ‘);
            flag[i]:=true;
              for j:=1 to c[i] do dec(d[map[i,j]]);
                break;
          end;
    end;
end.

高精度·加法

var s1,s2:string;
    a,b:array[1..100] of longint;
    la,le,len,i:longint;
begin
  readln(s1);
  readln(s2);
  la:=length(s1);
  for i:= 1 to la do a[i]:=ord(s1[la+1-i])-48;
  le:=length(s2);
  for i:=1 to le do b[i]:=ord(s2[le+1-i])-48;
  len:=la;
  if le>len then len:=le;
  for i:=1 to len do
    begin
      a[i+1]:=a[i+1]+(a[i]+b[i]) div 10;
      a[i]:=(a[i]+b[i]) mod 10;
    end;
  if a[len+1]>0 then len:=len+1;{判断最高位}
  for i:=len downto 1 do write(a[i]);
end.

高精度·减法

const n=1000;
type arr=array[0..n]of longint;
var a,b:arr;s:string;
function f:boolean;
var i:longint=1;
begin
  f:=true;
  while ((i<n)and(a[i]=b[i])) do inc(i);
  if a[i]<=b[i] then f:=false;
end;
procedure init(var p:arr);
var m:char;
    k,i:longint;
begin
   k:=1;
   read(m);
   while m in[‘0‘..‘9‘] do
   begin
      p[k]:=ord(m)-48;k:=k+1;read(m);{使得能够不断读数}
   end;
   for i:=1 to k do
   begin
      p[n+i-k]:=p[i];p[i]:=0;{把最小位放在前面,便于顺次详见}
   end;
end;
procedure work;
var t,g:longint;i:longint;
begin
  if f then write(‘‘);
  if not f then
  begin
  s:=‘-‘;
{判断减数和被减数大小,如果被减数大于减数就填负号后交换位置}
  for i:=1 to n do
   begin
    t:=a[i];a[i]:=b[i];b[i]:=t;
   end;
  end;
   g:=0;{进位标志}
  for i:=n downto 1 do
  begin
  if a[i]>=b[i]+g then
  begin
   a[i]:=a[i]-b[i]-g;g:=0;
  end{不需要借位时}
  else
  begin
   a[i]:=10+a[i]-b[i]-g;g:=1;
  end;
  end;
end;
procedure output;
var i:longint=1;
begin
  while((a[i]=0)and(i<n))do inc(i);
{当在范围限度内且为零时就不断不断向后移以寻找做完减法后的最高位}
  while i<n do
  begin
   write(a[i]);inc(i);
  end;
end;
begin
  fillchar(a,sizeof(a),0);fillchar(b,sizeof(b),0);
  init(a); readln;
  init(b);readln;
  work;
  write(s);output;
end.

高精度·乘法

const max=200;
type arr=array[1..max]of longint;
     arrr=array[1..2*max] of longint;
var a,b:arr;c:arrr;k,s1,s2,n:longint;
procedure init(var p:arr);
var s:string; i:longint;
begin
   read(s);n:=length(s);
   if s=‘0‘ then
   begin
    write(‘0‘);halt;
   end;
   for i:=n downto 1 do
    p[n-i+1]:=ord(s[i])-48;{把小位数放在前面}
end;
procedure work;
var i,j,x,l:longint;
begin
  for i:=1 to s1 do
   for j:=1 to s2 do
   begin
    l:=a[i]*b[j];
c[i+j-1]:=c[i+j-1]+l;
{解决错位相加问题,a、b数组的值正好放在c数组【i+j-1】的位置上,就可以用这个位置原来的数加上新乘出的数解决问题,在运算过程中,a、b数组里面的值不能改变,所以必须要新开一个新数组}
   end;
  for i:=1 to k do
    begin
      c[i+j]:=c[i+j]+c[i+j-1] div 10;
{这一步必须在前面否则下面一步就改变了c数组里面的值}
      c[i+j-1]:=c[i+j-1] mod 10;
    end;
  while c[k]=0 do dec(k);{寻找最高位}
  x:=c[k];
  while x>0 do
   begin
    c[k]:=x mod 10;
    x:=x div 10;
    inc(k);
   end;{解决最高位问题}
end;
procedure output;
var i:longint;
begin
 for i:=k-1 downto 1 do write(c[i]);
end;
begin
  fillchar(a,sizeof(a),0); fillchar(b,sizeof(b),0);fillchar(c,sizeof(c),0);
  init(a);readln;s1:=n;
  init(b);readln; s2:=n;
  k:=s1+s2; {乘法得出结果后的最高位数为两个位数的因数之和}
  work;output;
end.

高精度·除法

type arr=array[0..10000]of longint;
var a,b,c,d:arr;a1,b1,n,j,I,len:longint;s,s1,s2:string;
procedure init;
begin
  readln(s);len:=length(s);
  a1:=pos(‘ ‘,s);s1:=copy(s,1,a1-1);s2:=copy(s,a1+1,len-a1);a1:=length(s1);
  for i:=1 to a1 do a[i]:=ord(s1[a1-i+1])-48;
  b[0]:=length(s2);
  for i:=1 to b[0] do b[i]:=ord(s2[b[0]-i+1])-48;
end;
function f:boolean;
var i:longint;
begin
  if d[0]>b[0] then exit(true);
  if d[0]<b[0] then exit(false);
  for i:=d[0] downto 1 do
  begin
   if d[i]>b[i] then exit(true)
   else if d[i]<b[i] then exit(false);
  end;
  exit(true);
end;
procedure change(x:longint);
var i:longint;
begin
  inc(d[0]);
  for i:=d[0] downto 2 do d[i]:=d[i-1];
  d[1]:=x;
end;
function work:boolean;
var i:longint;
begin
  if f=false then exit(false);
  for i:=1 to d[0] do
    begin
     d[i+1]:=d[i+1]-1+(d[i]+10-b[i]) div 10;
     d[i]:=(d[i]+10-b[i])mod 10;
    end;
  while (d[d[0]]=0) and(d[0]>1) do dec(d[0]);
  exit(true);
end;
procedure output;
var i:longint;
begin
  while (c[a1]=0) and(a1>1) do dec(a1);
  for i:=a1 downto 1 do write(c[i]);
  writeln;
end;
begin
  fillchar(a,sizeof(a),0);
  fillchar(b,sizeof(b),0);
  fillchar(c,sizeof(c),0);
  fillchar(d,sizeof(d),0);
  init;
  if a1<b[0] then
   begin
    write(‘0...‘);
    for j:=a1 downto 1 do write(a[j]);
    halt;
   end;
  for j:=a1 downto 1 do
   begin
    change(a[j]);
    while work do inc(c[j]);
   end;
  output;
end.

高精度·阶乘

{高精度乘单精度}
const max=2000;
var a:array[1..max] of longint;n,i,j,l,q:longint;
begin
  readln(n);
  a[1]:=1;l:=1;
{l表示前面的数依次的阶乘}
  for i:=2 to n do
  begin
    for j:=1 to l do a[j]:=a[j]*i;{做乘法}
    for j:=1 to l do
    begin
      a[j+1]:=a[j+1]+a[j] div 10;
      a[j]:=a[j] mod 10;{处理进位问题}
    while a[l+1]<>0 do
    begin
      l:=l+1;
      a[l+1]:=a[l+1]+a[l] div 10;
      a[l]:=a[l] mod 10;
end;
{处理最高位及数位问题}
    end;
  end;
  for i:=l downto 1 do write(a[i]);
end.

排序-快速排序

    procedure sort(l,r:longint);
      var i,j,x,y:longint;
      begin
         i:=l;j:=r;
         x:=a[(l+r) div 2];
         repeat
           while a[i]<x do inc(i);
           while x<a[j] do dec(j);
           if not(i>j) then
             begin
                y:=a[i];a[i]:=a[j];a[j]:=y;
                inc(i);dec(j);
             end;
         until i>j;
         if l<j then sort(l,j);
         if i<r then sort(i,r);
      end;

排序-归并排序

var n,i,ans:longint;
a,t:array[0..40005]of longint;
procedure mergesort(l,r:longint);
var mid,i,j,x:longint;
begin
  if (r-l)<=1 then exit;
  //分治三步法:
  //一.划分
  mid:=l+(r-l) div 2;
  i:=l; j:=mid; x:=i;  //i,j表示两个合并的序列的首坐标;
                       //x表示当前修改到第几个元素
  //递归求解
  mergesort(l,mid);
  mergesort(mid,r);
  //合并
  while (i<mid)or(j<r) do
    begin
      if (j>=r)or((i<mid)and(a[i]<=a[j])) then
        begin
          t[x]:=a[i]; inc(x); inc(i);
        end
          else
            begin
              t[x]:=a[j]; inc(x); inc(j);
              //统计左边大于右边的:
              //在区间[l,mid)中,共有元素(mid-l)个
              //其中进入上个条件的有(i-l)个
              //相减得到(mid-i)个
              ans:=ans+(mid-i);
            end;
    end;
  for i:=l to r-1 do a[i]:=t[i];
end;

begin
  readln(n);
  for i:=1 to n do read(a[i]);
  mergesort(1,n+1);
  writeln(ans);
end.

数位dp

typedef long long ll;
int a[20];
ll dp[20][state];//不同题目状态不同
ll dfs(int pos,/*state变量*/,bool lead/*前导零*/,bool limit/*数位上界变量*/)//不是每个题都要判断前导零
{
    //递归边界,既然是按位枚举,最低位是0,那么pos==-1说明这个数我枚举完了
    if(pos==-1) return 1;/*这里一般返回1,表示你枚举的这个数是合法的,那么这里就需要你在枚举时必须每一位都要满足题目条件,也就是说当前枚举到pos位,一定要保证前面已经枚举的数位是合法的。不过具体题目不同或者写法不同的话不一定要返回1 */
    //第二个就是记忆化(在此前可能不同题目还能有一些剪枝)
    if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];
    /*常规写法都是在没有限制的条件记忆化,这里与下面记录状态是对应,具体为什么是有条件的记忆化后面会讲*/
    int up=limit?a[pos]:9;//根据limit判断枚举的上界up;这个的例子前面用213讲过了
    ll ans=0;
    //开始计数
    for(int i=0;i<=up;i++)//枚举,然后把不同情况的个数加到ans就可以了
    {
        if() ...
        else if()...
        ans+=dfs(pos-1,/*状态转移*/,lead && i==0,limit && i==a[pos]) //最后两个变量传参都是这样写的
        /*这里还算比较灵活,不过做几个题就觉得这里也是套路了
        大概就是说,我当前数位枚举的数是i,然后根据题目的约束条件分类讨论
        去计算不同情况下的个数,还有要根据state变量来保证i的合法性,比如题目
        要求数位上不能有62连续出现,那么就是state就是要保存前一位pre,然后分类,
        前一位如果是6那么这意味就不能是2,这里一定要保存枚举的这个数是合法*/
    }
    //计算完,记录状态
    if(!limit && !lead) dp[pos][state]=ans;
    /*这里对应上面的记忆化,在一定条件下时记录,保证一致性,当然如果约束条件不需要考虑lead,这里就是lead就完全不用考虑了*/
    return ans;
}
ll solve(ll x)
{
    int pos=0;
    while(x)//把数位都分解出来
    {
        a[pos++]=x%10;//个人老是喜欢编号为[0,pos),看不惯的就按自己习惯来,反正注意数位边界就行
        x/=10;
    }
    return dfs(pos-1/*从最高位开始枚举*/,/*一系列状态 */,true,true);//刚开始最高位都是有限制并且有前导零的,显然比最高位还要高的一位视为0嘛
}
int main()
{
    ll le,ri;
    while(~scanf("%lld%lld",&le,&ri))
    {
        //初始化dp数组为-1,这里还有更加优美的优化,后面讲
        printf("%lld\n",solve(ri)-solve(le-1));
    }
}  

双哈希

const p1=6662333;
      p2=100000123;
      x1=31;
      x2=29;
var n,i,ans:longint;
s:ansistring;
a,b:array[0..10000]of longint;
    procedure sort(l,r: longint);
      var i,j,x,y: longint;
      begin
         i:=l; j:=r;
         x:=a[(l+r) div 2];
         repeat
           while a[i]<x do inc(i);
           while x<a[j] do dec(j);
           if not(i>j) then
             begin
                y:=a[i];a[i]:=a[j];a[j]:=y;
                y:=b[i];b[i]:=b[j];b[j]:=y;
                inc(i); j:=j-1;
             end;
         until i>j;
         if l<j then sort(l,j);
         if i<r then sort(i,r);
      end;
function hash1:longint;
var i:longint;
begin
  hash1:=0;
  for i:=1 to length(s) do
    hash1:=(hash1*x1+ord(s[i])-ord(‘a‘))mod p1;
end;
function hash2:longint;
var i:longint;
begin
  hash2:=0;
  for i:=1 to length(s) do
    hash2:=(hash2*x2+ord(s[i])-ord(‘a‘)) mod p2;
end;
begin
  readln(n);
  for i:=1 to n do
    begin
      readln(s);
      a[i]:=hash1;
      b[i]:=hash2;
    end;
  sort(1,n);
  ans:=1;
  for i:=2 to n do
    if (a[i]<>a[i-1])or(b[i]<>b[i-1]) then ans:=ans+1;
  writeln(ans);
end.

Tarjan缩点

var
next,head,key,next1,head1,key1:array[0..50000]of longint;
tot,totc,tott,count,top,a,b,m,n,i,ans,num,j,v,u,x:longint;
DFN,Low,stack,q,belong,size:array[0..10000]of longint;
flag:array[0..10000]of boolean;
procedure add(u,v:longint);
begin
  tot:=tot+1;
  next[tot]:=head[u];
  head[u]:=tot;
  key[tot]:=v;
end;
procedure add1(u,v:longint);
begin
  tott:=tott+1;
  next1[tott]:=head1[u];
  head1[u]:=tott;
  key1[tott]:=v;
  inc(q[u]);
end;
procedure Tarjan(u:longint);
var i,v,j:longint;
begin
  count:=count+1;
  DFN[u]:=count; LOW[u]:=count;
  top:=top+1;
  stack[top]:=u;
  flag[u]:=true;
  i:=head[u];
  while (i<>-1) do
  begin
    v:=key[i];
    if dfn[v]=0 then
      begin
        Tarjan(v);
        if low[v]<low[u] then low[u]:=low[v];
      end
      else if (dfn[v]<low[u])and(flag[v]) then low[u]:=dfn[v];
    i:=next[i];
  end;
  if low[u]=dfn[u] then
    begin
      inc(totc);
      repeat
        j:=stack[top];
        top:=top-1;
        flag[j]:=false;
        belong[j]:=totc;
        inc(size[totc]);
      until j=u;
    end;
end;
begin
  fillchar(next,sizeof(next),-1);
  fillchar(head,sizeof(head),-1);
  readln(n,m);
  ans:=0;
  for i:=1 to m do
    begin
      read(a,b);
      add(a,b);
    end;
  fillchar(flag,sizeof(flag),true);
  for i:=1 to n do
    if DFN[i]=0 then
      Tarjan(i);
  for u:=1 to n do
    begin
      i:=head[u];
      while i<>-1 do
        begin
          v:=key[i];
          if belong[u]<>belong[v] then add1(belong[u],belong[v]);
          i:=next[i];
        end;
    end;
  x:=0;
  for i:=1 to totc do
    if q[i]=0 then begin x:=x+1; ans:=size[i]; end;
  if x=1 then writeln(ans)
    else writeln(0);
end.

Tarjan求LCA

var
head,next,key,head1,key1,size,next1,fa,ans:array[0..1000010]of longint;
vis:array[0..1000010]of boolean;
tot1,tot,T,i:longint;
procedure add(x,y:longint);
begin
  tot:=tot+1;
  next[tot]:=head[x];
  head[x]:=tot;
  key[tot]:=y;
end;
procedure add1(x,y,z:longint);
begin
  tot1:=tot1+1;
  next1[tot1]:=head1[x];
  head1[x]:=tot1;
  key1[tot1]:=y;
  size[tot1]:=z;
end;
function getfather(x:longint):longint;
begin
  if fa[x]=x then exit(x)
   else begin fa[x]:=getfather(fa[x]); exit(fa[x]); end;
end;
procedure Tarjan_LCA(u,pre:longint);
var  i,v:longint;
begin
  fa[u]:=u;
  i:=head[u];
  while i>0 do
    begin
      v:=key[i];
      if v=pre then begin i:=next[i]; continue; end;
      Tarjan_LCA(v,u);
      fa[v]:=u;
      i:=next[i];
    end;
  vis[u]:=true;
  i:=head1[u];
  while i>0 do
    begin
      v:=key1[i];
      if vis[v]=false then begin i:=next1[i]; continue; end;
      ans[size[i]]:=getfather(v);
      i:=next1[i];
    end;
end;
procedure make;
var i,x,y,n,m,s:longint;
begin
  fillchar(ans,sizeof(ans),0);
  readln(n,m,s);
  for i:=1 to n-1 do
    begin
      readln(x,y);
      add(x,y);add(y,x);
    end;
  for i:=1 to m do
    begin
      readln(x,y);
      add1(x,y,i); add1(y,x,i);
    end;
  tarjan_LCA(s,0);
  for i:=1 to m do writeln(ans[i]);
end;
begin
  make;
end.

倍增求LCA

var  n,m,s,i,u,v,a,b,tot,j:longint;
next,head,key,deep:array[0..1000000]of longint;
father:array[0..500000,0..20]of longint;
function swap(var a,b:longint):longint;
var t:longint;
begin t:=a; a:=b; b:=t; end;
procedure add(u,v:longint);
begin
    inc(tot);
    next[tot]:=head[u];
    head[u]:=tot;
    key[tot]:=v;
end;
procedure dfs(x:longint);
var i:longint;
begin
    deep[x]:=deep[father[x,0]]+1;
    i:=0;
    while father[x,i]>0 do
        begin
            father[x,i+1]:=father[father[x,i],i];
            inc(i);
        end;
    i:=head[x];
    while i>0 do
        begin
            if deep[key[i]]=0 then
                begin
                    father[key[i],0]:=x;
                    dfs(key[i]);
                end;
            i:=next[i];
        end;
end;
function LCA(x,y:longint):longint;
var i:longint;
begin
    if deep[x]>deep[y] then swap(x,y);
    for i:=19 downto 0 do
        if (deep[father[y,i]]>=deep[x]) then
            y:=father[y,i];
    if x=y then exit(y);
    for i:=19 downto 0 do
        if father[y,i]<>father[x,i] then
            begin
                y:=father[y,i];
                x:=father[x,i];
            end;
    exit(father[x,0]);
end;
begin
    tot:=0;
    read(n,m,s);
    for i:=1 to n-1 do
        begin
            read(u,v);
            add(u,v); add(v,u);
        end;
    dfs(s);
    for i:=1 to m do
        begin
            read(a,b);
            writeln(LCA(a,b));
        end;
end.

暂且更新到这里。

时间: 2024-11-10 00:55:54

模板总复习的相关文章

C++智能指针模板类复习

//C++智能指针模板类复习 #include<iostream> #include<memory> using namespace std; //智能指针用于确保程序不存在内存和资源泄漏且是异常安全的. //C++98中提供了auto_ptr,C++11摒弃了auto_ptr,并提出了unique_ptr .shared_ptr.weak_ptr void show1() { int* p = new int(4); cout << *p << endl;

EF6 在原有数据库中使用 CodeFirst 总复习(五、生成发帖页面)

有点与在原有数据库中使用 CodeFirst 远了,不过是总复习吗,总得全面点. 一.在用户表(Users)中插入两个用户 二.生成发帖界面 MVC生成的界面很多,也没使用Ajax,实际开发中很少会使用,这里只是为了演示. 但无论用什么生成,特性.实体对象等都是要用到的. 生成之前要编译一下. 三.先试试看能不能运行 空空如也 应该显示用户名,显示成登陆名了(其实预想的是不在新增和修改时显示,未考虑到列表),删除标记怎么也显示出来了,还有内容,能显示的下吗... 四.列显示问题 让列表显示用户,

[家里蹲大学数学杂志]第240期钟玉泉编复变函数总复习纲要

第240期_钟玉泉编复变函数总复习纲要 下载后请自行打印.预览或学习, 不要到处传播于网络, 更不要用于商业用途.

2016年初中数学知识点中考总复习总结归纳

2016年初中数学知识点中考总复习总结归纳 http://wenku.baidu.com/link?url=NbEiI_Ld2TO3zEH8d5oDxTux2IBWJ5HqNmZ467MGchJTV2G0pyG4_TauOsYhjL6Ybyqp8MxUKM_wtofUqMTc7ePR3gJv3zIY27sTuSGOaRW

C++模板类复习

//C++模板类复习 #include<iostream> using namespace std; template <class T1, class T2 = string> class test { private: T1 temp1; T2 temp2; public: test(){} test(T1 data1, T2 data2):temp1(data1),temp2(data2){} void show(); }; template <class T1, cl

实验十八 总复习

实验十八  总复习 实验时间 2018-12-30 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设计结构: (4) 综合掌握java多线程编程模型: (5) 综合编程练习. 2.实验内容和步骤 任务1:填写课程课后调查问卷,网址:https://www.wjx.cn/jq/33108969.aspx. 任务2:综合编程练习 练习1:设计一个用户信息采集程序,要求如下: (1)  用户信息输入界面

P2 总复习

目录 0531总复习 数据类型内置方法 整形类型内置方法 浮点型类型内置方法 字符串类型内置方法 优先掌握 需要掌握 了解 列表类型内置方法 优先掌握 需要掌握 元组类型内置方法 优先掌握 字典类型内置方法 优先掌握 需要掌握 集合类型内置方法 优先掌握 需要掌握 数据类型总结 可变or不可变 有序or无需 存一个值or多个值 拷贝 浅拷贝 深拷贝 字符编码 Python3解释器编码 文件操作 打开文件的流程 with管理上下文 打卡文件的三种模式 同时打开两个文件 文件复制 打开文件file后

0505.Net基础班第二十一天(基础加强总复习)

1.取消播放器的自动播放功能 2.播放或者暂停按钮 3.下一曲.上一曲 4.多选删除 5.静音和放音 6.选择列表中的音乐文件,单击播放按钮直接播放 7.自动进行下一曲 15秒  44秒 当我和世界不一样 44.--47 那就让我不一样 lblInfomation.Text = musicPlayer.currentMedia.duration.ToString() + "\r\n" + musicPlayer.currentMedia.durationString + "\

Java面向对象总复习-QuickHit

1.创建玩家级别类Level.java 1 package com.bdqn; 2 /** 3 * 1.玩家级别类 4 * @author pc 5 * 6 */ 7 public class Level { 8 /** 9 * 级别号 10 */ 11 private int levelNo; 12 /** 13 * 各级别一次输出字符串的长度 14 */ 15 private int strLength; 16 /** 17 * 各级别输出字符串的次数 18 */ 19 private in