码迷,mamicode.com
首页 > 其他好文 > 详细

模板总复习

时间:2017-11-03 23:48:45      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:加法   去掉   最短路   sans   pat   graph   lin   结合   缩点   

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

每天一个部分好啦。

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

快速幂

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

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

11的二进制是101111 = 21 + 20 + 21 + 21,因此,我们将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=y0y=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.

 

暂且更新到这里。

模板总复习

标签:加法   去掉   最短路   sans   pat   graph   lin   结合   缩点   

原文地址:http://www.cnblogs.com/Hathawaxy/p/7768782.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!